【Rails】ネストしたルーティングのURLのidが入れ替わる問題への対処法

例えば、postモデルを親としてitemモデルのルーティングを以下のようにネストした場合、

resources :posts do
  resources :items
end

showページ、およびeditページを表示した際にネストしたitemモデルのルーティングのURLのidが入れ替わって表示される(idパラメータが正常に受け取れない)という問題が発生してしまいました。

【例】
(こう表示したいのに)
http://localhost:3000/posts/1/items/123

(こう表示されてしまう)
http://localhost:3000/posts/123/items/1

本来、itemモデル(itemsコントローラー)のshowページ、およびeditページにおけるルーティングは以下のようになるかと思いますが、

     post_item_path GET    /posts/:post_id/items/:id/(.:format)       items#show
edit_post_item_path GET    /posts/:post_id/items/:id/edit(.:format)   items#edit

実際には上記の:post_id:idが入れ替わってURL欄に表示されてしまうのです。

本記事はその問題へのトラブルシューティングです。

目次

ネストしたルーティングのULRのidが前後入れ替わる問題発生

問題の概要は先ほど説明したとおりですが、

例えば、itemモデルのshowページにアクセスするとしましょう。

itemモデルのshowページにアクセスするためにはpost_iditem_idがそれぞれ必要になりますが、

post_iditem_idがそれぞれ以下の値のとき、

  • post_id:1
  • item_id:123

showページに表示されるURLは以下のようになるはずです。

【期待するURL】
http://localhost:3000/posts/1/items/123

しかし、実際にはURL欄に以下のように表示されてしまいます。

【実際に表示されるURL】
http://localhost:3000/posts/123/items/1

これを、ルーティングに置き換えて見てみると、

【こうしたいのに】
http://localhost:3000/posts/:post_id/items/:id

【実際はこのような表示になる】
http://localhost:3000/posts/:id/items/:post_id

このように、post_id(:post_id)とitem_id(:id)が前後入れ替わってしまっていますね。

問題の解決策

post_item_path GET    /posts/:post_id/items/:id/(.:format)       items#show

ネストされたitemモデルのルーティングに則り、URLの左から順にpost_id(:post_id)、item_id(:id)と表示されるようにしたいので、

showページへのパスを貼る際に、itemモデルのshowページ(もしくはeditページ)へのパスの引数に、以下のようにidの順番を指定すればOKです。

# 同一URLにidを左から順に表示させるよう、以下のようにidの順番を指定
<%= link_to "◯◯", post_item_path(@item.post_id, @item.id) %>

こうすることで、同一URL内に複数のidパラメータが存在する場合も、狙い通りの順番でidを表示させることができます。

【パスにidの順番を指定することで解決】
http://localhost:3000/posts/:post_id/items/:id

editページへのパスも同様にします。

# editパスも同様にidの順番を指定
<%= link_to "◯◯", edit_post_item_path(@item.post_id, @item.id) %>

あとは、items_controller.rbに以下のコードを追記すれば指定したパスにアクセスできるようになります。

class ItemsController < ApplicationController
  before_action :set_post
  before_action :set_item, only: %i[ show edit update destroy ]

  ・・・

  private
    def set_post
      @post = Post.find(params[:post_id])
    end

    def set_item
      @item = Item.find(params[:id])
    end

  ・・・

end

以上です。

関連記事

あわせて読みたい
【Rails】ネストしたモデルに対するform_withの書き方 例えば以下のように、一つの投稿(post)の中にさらに複数の投稿(item)を追加できるようにしたい場合、 そんな時は、idなどのパラメータの受け渡しの都合上、ルーティング...

参考記事

Stack Overflow
Rails nested routes wrong id At the moment I have a nested routes associated between my map and rows where a row has_many rows. resources :maps do resources :rows end While looking in my ra...
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

愛知の34歳。無職で暇になり始めたプログラミング(Ruby on Rails)の忘備録をまとめたブログです。最近は別にやりたいことができたのでプログラミングほぼやっていません。気が向いたらまた再開するかも。僕の日常はメインブログの方で更新しています。

コメント

コメントする

目次