Railsのroutes.rbで使用できるresolveメソッドについて紹介します。resolveメソッドは、polymorphic_pathやpolymorphic_urlにモデルインスタンスを渡した際に生成されるURLをカスタマイズできます。
resolveとは
Railsのビューヘルパーでは、link_to 'title', @postのように、URLが必要とされる箇所でモデルインスタンスを直接渡すことができます。このとき、内部ではpolymorphic_pathによってURLが生成されています。resolveを使用することで、この生成されるURLを柔軟に変更することが可能になります。
polymorphic_pathの挙動
polymorphic_pathには、主にモデルインスタンスやシンボル、またはそれらの配列を渡すことができます。
-
モデルインスタンスの場合:
persisted?(データベースに保存済みかどうか)によって、単数形(モデルインスタンスの引数つき)または複数形のURLヘルパーが使用されます。例えば、@postが保存済みであればpost_path(@post)、未保存であればposts_pathが使用されます。 -
シンボルの場合: そのシンボル名に対応するURLヘルパーが使用されます。例えば、
:basketであればbasket_pathが使用されます。 -
配列の場合: 配列の先頭から順に、中身に応じて名前を
_で連結したURLヘルパーが組み立てられます。モデルインスタンスとシンボルが混在している場合も、上記ルールに従って処理されます(詳細は後述)。
単数リソースにおけるresolveの活用
単数リソース(例えば、resource :basket)の場合、form_with model: @basket do |f|のように記述すると、内部でpolymorphic_path(@basket)が実行され、通常はbasket_path(@basket)が呼ばれ、URLは/baskets/:idとなります。しかし、単数リソースでは/basketというURLを期待する場合が多いです。
このような場合に、resolveが役立ちます。以下のように定義することで、polymorphic_path(@basket)がpolymorphic_path([:basket])と同様に扱われるようになります1。
resolve "Basket" do
[:basket]
end
この定義により、polymorphic_path(@basket)の内部でこの定義が参照され、シンボル:basketからbasket_pathが組み立てられ(引数なし)、URLは/basketとなります。
URLの配列記法とネストされたリソース
polymorphic_pathには配列を渡すことができ、これはネストされたリソースや名前空間内のリソースを指す際に便利です。
-
polymorphic_path([@post, @comment])はpost_comment_path(@post, @comment)に相当します。 -
polymorphic_path([:admin, @post])はadmin_post_path(@post)に相当します。
ネストされたリソースの場合、resolveを使って子リソースのインスタンスのみからネストされたURLを生成することができます。
resolve "Comment" do |comment|
[comment.post, comment]
end
この定義により、polymorphic_path(@comment)は/posts/:post_id/comments/:idというURLを生成するようになります。これにより、link_to "コメント", @commentのように簡潔に記述することができます。
まとめ
resolveの利用法として単数リソースのURLを調整したり、ネストされたリソースのURLを簡略化する例を挙げましたが、他にももっと複雑なURLのルールを作るときにも便利です。活用してみましょう!
References
-
要素が1つだけなので配列
[:basket]ではなく単に:basketでも問題ありませんが、Railsガイドやリファレンスマニュアルでは配列で記述されていることが多いため、ここではそれに倣っています。また、実際の動作はpolymorphic_url([:basket])が呼ばれた後、パス部分だけが抜き出されます。 ↩