Railsにはよく使うものとしてlink_to
やbutton_to
があります。これらはリンクやボタンを生成するヘルパーです。
更に、遷移先のURLやpathを指定することが出来て、以下のように書けます。
<%= link_to '詳細へ', user_path(user.id) %>
では、URLのネストをした場合、xxx_path
はどうなるでしょうか?
例えば、ユーザーは記事を投稿でき、その記事たちをお気に入りに追加できる機能があったとします。
ルーティングはこちら
Rails.application.routes.draw do
# ユーザーは記事を投稿できる
resources :users do
resources :articles do
# 記事をお気に入りすることができる
resources :favorites
end
end
end
rails routesを叩いてxxx_path
の部分を見てみましょう。
お気に入りの新規保存に使えるであろうfavorites#createはuser_article_favorites
になってます。
これはまだマシですが、もっとネストされたら長くなり、xxx_path
の部分が分かり辛くなるでしょう。
$ rails routes
user_article_favorites GET /users/:user_id/articles/:article_id/favorites(.:format) favorites#index
POST /users/:user_id/articles/:article_id/favorites(.:format) favorites#create
new_user_article_favorite GET /users/:user_id/articles/:article_id/favorites/new(.:format) favorites#new
edit_user_article_favorite GET /users/:user_id/articles/:article_id/favorites/:id/edit(.:format) favorites#edit
user_article_favorite GET /users/:user_id/articles/:article_id/favorites/:id(.:format) favorites#show
PATCH /users/:user_id/articles/:article_id/favorites/:id(.:format) favorites#update
PUT /users/:user_id/articles/:article_id/favorites/:id(.:format) favorites#update
DELETE /users/:user_id/articles/:article_id/favorites/:id(.:format) favorites#destroy
本題(polymophic_path)を使おう!
Railsにはモデルから生成されたインスタンスに対して、ルーティングをスマートに書ける方法が提供されています。
公式ドキュメントはこちら
結論から言うと、こう書いていたものが、
# user = User.find(1)
# article = Article.find(1)
<%= button_to 'お気に入りする', user_article_favorites_path(user.id, article.id), method: :post %>
こう書けます
<%= link_to 'お気に入りする', polymorphic_path([user, article, :favorites]), method: :post %>
何をしているかと言うと、polymorphic_pathの引数においたモデルインスタンスを元にリンクを生成してくれています。
今回の場合 users/1/articles/1/favorites
が生成されています。
ポイントは以下の3つです。
- 基本的に引数にはModelのインスタンスを置く
- 引数を複数置きたい場合は配列で囲む
- インスタンスの生成が行われていない場合は、
:favorites
のようにシンボル型で引数に置く
今回の例よりさらに複雑になったpathであれば可読性はさらに向上すると思います。
(逆にusers_pathといった短いものにpolymorphic_pathを使うと変に見えるかもしれません。)
polymorphic_pathの応用
先ほどとは別にnewアクションやeditアクションへのリンクを生成したい場合は以下のように書くこともできます。
# user = User.find(1)
# article = Article.find(1)
<%= link_to '編集へ', edit_polymorphic_path([user, article ]) %>
<%= link_to '新規作成へ', new_polymorphic_path([user, article ]) %>
edit_polymorphic_path([user, article ])
の場合、users/1/articles/1/edit
のようなリンクが生成されます。
まとめ
RailsにはDRYの法則に則ったヘルパーやメソッドがたくさん用意されています。
今回扱ったpolymorphic_pathは長くなりがちなpathの記述を簡潔に書くことができます。
ぜひお試しください!