入れ子になったルート内で Ruby on Rails ポリモーフィック関連付けを操作するにはどうすればよいですか
概要
私の質問をより明確に正しくするために編集されました。 私はポリモーフィックな関連付けを実装するためにいくつかのパターンを試しましたが、数年前に GoRails の Chris から選んだパターンに落ち着きました。これは堅牢であり、ポリモーフィックな関連付けを実装するほぼすべてのトップレベルのリソースで動作します。簡単な例は、Taskable を多態性関連付けとして公開する Tasks モデルです。プロジェクトなどの単一の最上位オブジェクトとの関連付けを簡単に設定できます。 例 (すべてのコードは当面の質問に限定されています):
app/models/task.rb
class Task < ApplicationRecord
belongs_to :taskable, polymorphic: true
end
アプリ/モデル/プロジェクト.rb
class Project < ApplicationRecord
has_many :phases
has_many :tasks, as: :taskable
end
app/controllers/tasks_controller.rb
class TasksController < ApplicationController
def new
@task = @taskable.tasks.new
end
# lots of other methods...
end
app/controllers/projects/tasks_controller.rb
class Projects::TasksController < TasksController
before_action :set_taskable
private
def set_taskable
@taskable = Project.find(params[:project_id])
end
end
config/routes.rb
Rails.application.routes.draw do
resources :projects do
resources :phases
resources :tasks, module: :projects
end
end
したがって、どのビューでも次のようにリンクを追加できます。 app/views/tasks/show.html.erb
<%= link_to 'Edit task', edit_polymorphic_path([@taskable, @task]) %>
このパターンを使用すると、コードの重複を最小限に抑えて (懸念事項を使用せずに)、あらゆるオブジェクトをタスクに簡単に接続できます。
問題は、ネストされたオブジェクトを接続する必要があるときに発生します。ルート ファイルでは、プロジェクトがフェーズと 1 対多の関係にあることに注意してください。ここで、フェーズをポリモーフィックな関連付けに接続する必要がある場合 (ここでは例としてタスクを使用します)、ポリモーフィック パスまたは URL を 3 つの部分からなる表記で作成する必要があります: <%= link_to ‘Edit task’, edit_polymorphic_path( [@プロジェクト、@タスク可能、@タスク]) %> 頭を悩ませてあちこち探しましたが、何も見つかりませんでした。どこから始めればよいのかさえ思いつきません。
最初にルートを次のように設定しました。
Rails.application.routes.draw do
resources :projects do
resources :phases do
resources :tasks, module: :phases
end
resources :tasks, module: :projects
end
end
ルートは正しく出力されますが、パス呼び出しに 3 つのパラメータを渡す必要があります。 <%= link_to ‘タスクの編集’, edit_polymorphic_path([@project, @taskable, @task]) %> ただし、引数リストが異なるため、これは私のポリモーフィックなビューを壊します。したがって、ポリモーフィックな関連付けのルーティング レベルに関係なく、ビューをポリモーフィックに保つ方法を探しています。
私もこれを機能させようとしました: config/routes.rb
Rails.application.routes.draw do
resources :projects do
resources :phases
resources :tasks, module: :projects
end
resources :phases do
resources :tasks, module: :phases
end
end
もちろん、Rails はこれを好みません。両方の関連付けが 2 番目のブロックで表現されていないため、完全なルートを作成できないからです。
助けていただきありがとうございます。
解決策
ここで問題が何であるかを見逃しているかもしれませんが、ルートをネストし続けることができます。
Rails.application.routes.draw do
resources :projects do
resources :phases do
resources :tasks, module: :phases
end
resources :tasks, module: :projects
end
end
# Prefix Verb URI Pattern Controller#Action
edit_project_phase_task GET /projects/:project_id/phases/:phase_id/tasks/:id/edit(.:format) phases/tasks#edit
アップデート
したがって、2 つのルートがあり、それをタスク用の 1 つのテンプレートから使用したいとします。
edit_polymorphic_path([@taskable, @task]) # @taskable is Project
edit_polymorphic_path([@project, @taskable, @task]) # @taskable is Phase
すべてに二重にネストされたルートをいつでも使用できます。
# this will work with @project or without
edit_polymorphic_path([@project, @taskable, @task])
例えば:
<%= edit_polymorphic_path([Project.first, Phase.first, Task.first]) %>
#=> /projects/1/phases/1/tasks/1/edit
<%= edit_polymorphic_path([nil, Project.first, Task.first]) %>
#=> /projects/1/tasks/1/edit