パラメーターでidを二つ送るのにてこずった話
ルーティングをネストしてパラメーターでidを2つ送りたかったときに、なかなかうまくいかずに困りました。
背景
登場するテーブルは二つです。
postsテーブル
reactionsテーブル
reactionsとpostsが1対多の関係になっています。
reactionsテーブルにはCommnetというアクティブハッシュと紐づいた、comment_idというカラムがあります。
やりたいこと
投稿の詳細ページのリンクを押す
↓
reactionsコントローラーのcreateに、post_idと合わせてcomment用のidを送りたい
<%= link_to "コメント1", xx_path(@post.id, 1), method: :post %>
こういう感じになるはず。
失敗その1
reactionsをpostにネストさせようと思って、config/routes.rb
に以下のように記述しました。
Rails.application.routes.draw do resources :posts do resources :reactions, only: :create end end
しかしこれではうまくいかず。
rails routes
で見てみると、これではpost_idしかパラメーターに入れられていないみたいです。
言われてみればresourcesのcreateアクションでは、普通フォームで値を送信して処理するのでidは必要ないですからね。
resourcesは使えなさそうです。
失敗その2
じゃあネストしないで自分で書いたらいいのではないかと思い、こうしてみました。
Rails.application.routes.draw do resources :posts post "/posts/:post_id/reactions/:id", to: "reactions#create" end
rails routes
で調べても、これならidを2つとも送れそうです。
しかし、結果的にはこれでもうまくいきませんでした。
リンクの方はこのようになっています。
<%= link_to "コメント1", post_path(@post.id, 1), method: :post %>
これでリンクをクリックするとエラーが起こり、ルーティングがおかしいと言われてしまいました。
なぜだ…post_pathでHTTPメソッドがPOSTで何がダメなんだ…。
ネストしていないあたりが問題かなあと思いつつ、はっきりした原因は未解決のまま、とりあえず別の方法を探しました。
失敗その3
上の二つの融合です。resourcesは使わないけどネストはさせて、自分で書けばいい。
Rails.application.routes.draw do resources :posts do post "/posts/:post_id/reactions/:id", to: "reactions#create" end end
これでrails routes
を見てみると
postsが繰り返してしまいました。ネストしたから前半は消さないとですね。でもこれで解決しそうです。
成功!
先ほどのものから重複した部分を消しました。
Rails.application.routes.draw do resources :posts do post "/reactions/:id", to: "reactions#create" end end
これで解決です。
と言いたいところなんですが。
prefixがrootになってますね。
流石にそれは違和感があるので、prefixも自分で決めました。
Rails.application.routes.draw do resources :posts do post "/reactions/:id", to: "reactions#create", as: "reactions" end end
ルーティングの名前は「:as」を使えば簡単に指定できます。
post_reactionsといういい感じの名前になりました。
今度こそ完成です。
まとめ
- リソースフルでないルーティングは自分で設定する
- ネストすべきところはネストする
- :asを使えばルーティングの名前を自分でつけられる