パラメーターでidを二つ送るのにてこずった話

f:id:endoakak:20200725103727j:plain

ルーティングをネストしてパラメーターで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しかパラメーターに入れられていないみたいです。

f:id:endoakak:20200824190319p:plain

言われてみれば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つとも送れそうです。

f:id:endoakak:20200824191028p:plain

しかし、結果的にはこれでもうまくいきませんでした。

リンクの方はこのようになっています。

<%= 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を見てみると

f:id:endoakak:20200824192518p:plain

postsが繰り返してしまいました。ネストしたから前半は消さないとですね。でもこれで解決しそうです。

成功!

先ほどのものから重複した部分を消しました。

Rails.application.routes.draw do
  resources :posts do
    post "/reactions/:id", to: "reactions#create"
  end
end

これで解決です。

と言いたいところなんですが。

f:id:endoakak:20200824192850p:plain

prefixがrootになってますね。

流石にそれは違和感があるので、prefixも自分で決めました。

Rails.application.routes.draw do
  resources :posts do
    post "/reactions/:id", to: "reactions#create", as: "reactions"
  end
end

ルーティングの名前は「:as」を使えば簡単に指定できます。

f:id:endoakak:20200824193357p:plain

post_reactionsといういい感じの名前になりました。

今度こそ完成です。

まとめ

  • リソースフルでないルーティングは自分で設定する
  • ネストすべきところはネストする
  • :asを使えばルーティングの名前を自分でつけられる