[Rails] ルーティングをシンプルにする方法(as・shallowについて)
はじめに
引き続き以前書いたコメント機能について、冗長性を修正したいと思います。
今回直したいのは、下記部分。
<%= link_to "削除", task_task_comment_path(task_comment.task, task_comment), method: :delete %>
task_task_comment_path
が長くてわかりにくいので、短縮したい。
asオプションを使う
config/routes.rb で asオプションを使用し、パスを短縮する。
resources :tasks do
resources :task_comments, as: "comments"
end
これにより、task_task_comments_path
は task_comments_path
に変わる。
<%= link_to "削除", task_comment_path(task_comment.task, task_comment), method: :delete %>
asオプションでのエラー
しかし、下記エラーが発生してしまった!
ActionView::Template::Error (undefined method `task_task_comments_path' for #<ActionView::Base:0x0000000003aca0>
recipient.public_send(method, *args, options)
^^^^^^^^^^^^
Did you mean? task_comments_path
task_comment_path):
80: <% end %>
81: <!-- コメント投稿フォーム -->
82:
83: <%= form_with model:[@task, @task_comment] do |f| %>
84: <%= f.text_area :comment, placeholder: "コメントを入力", class: "form-input-comment" %>
85: <%= button_tag(type: 'submit', class: 'submit-btn') do %>
86: <i class="fa-solid fa-paper-plane"></i>
app/views/public/tasks/show.html.erb:83
なぜエラーが起きたか?
resources :tasks do
resources :task_comments, as: "comments"
end
上記で、task_comments というリソースを comments という名前に変更している。
その結果、削除リンク内にある通常の task_task_comments_path パスが task_comments_path というパスに変更される。
下記が問題でエラーが起きてる。
<%= form_with model:[@task, @task_comment] do |f| %>
- @task が親リソース。
- @task_comment がその子リソース。
親子リソースの場合、親リソースのIDを含んだURLヘルパーを生成する。
つまり、task_task_comments_path
というパスヘルパーを生成する。
このヘルパーパスは as で変更したので、form_with内も修正が必要。
解決策
<%= form_with model: @task_comment, url: task_comments_path(@task), local: true do |f| %>
- 送信先を task_comments_path(@task) を指定する
-
model: @task_comment
を記載することで、@task_comment オブジェクトに関連付ける。これにより、フォームの送信後、task_comment モデルから生成されたインスタンスとして、データが保存される。
shallow の使用
routes.rbで、shallow: true を使用するやり方でも、task_comment_path が簡潔になる。
resources :tasks do
resources :task_comments, shallow: true
end
<%= form_with model: @task_comment, url: task_comments_path, local: true do |f| %>
shallow: true
オプションは、親リソースのIDを省略して書くことができる。
「shallow: true」は非推奨なのか?
「shallow: true」は賛否両論があり、プロジェクトによって使いどころが異なる。
深いネストを避けたいときは有効だが、一貫性を重視するなら使わない方がよい場合もある。
そのため、今回は as を使用しました。(shallow でも動いたけど、ルートの統一性を考えて as にした)
非推奨という意見
-
ルーティングの一貫性が失われる
ndex や new では /tasks/:task_id/task_comments なのに、show や edit では /task_comments/:id になり、URL の構造が統一されない。 -
リソースの所属が不明確になる
task_comments/:id
のようにtask_id
を省略すると、「このコメントはどのタスクに属しているのか?」が URL だけでは分からなくなる。
API の場合、/tasks/:task_id/task_comments/:id
のような構造の方が、データの関連性を明確にできる。 -
RESTful な設計の原則から外れる
「子リソースは親リソースに従属すべき」という考えに基づくと、show や edit でも task_id を持つべき。
しかし、「shallow: true」はRails の標準機能であり、公式に非推奨になってはいないらしい。
普通に使用してるコミュニティもあるっぽいので、これはケースバイケースでやっていくしかないなと思いました🤔
as: は ルート名(パスヘルパー)をカスタマイズするだけなので、ルーティングの構造を変えるshallow: とは異なり、一貫性問題は起きにくい。
(↑ここはもう少し理解を深めたい。長くなりすぎるので、明日調べようかな)
Discussion