Polymorphic URL 使うといいよ!という話
参考ページ:
Rails Best Practices - Generate polymorphic url
Rails初学者が出会うpathの生成ヘルパーから、一歩進んだパス生成方法について、グダグダと書く。
前提
例に使用するScaffold
$ ./bin/rails g scaffold Question title:string content:text
$ ./bin/rails g scaffold Answer content:text question:references
Question has_many Answers.
Answer belongs_to Question.
とする。
class Question < ActiveRecord::Base
has_many :answers
end
class Answer < ActiveRecord::Base
belongs_to :question
end
Routingは標準REST
親子関係があるので、ルーティングをネスト
(この方がネストしたリンクパスを生成する方法も一緒に書けるので)
resources :questions do
resources :answers
end
出来上がったルーティング
$ ./bin/rake routes
Prefix Verb URI Pattern Controller#Action
question_answers GET /questions/:question_id/answers(.:format) answers#index
POST /questions/:question_id/answers(.:format) answers#create
new_question_answer GET /questions/:question_id/answers/new(.:format) answers#new
edit_question_answer GET /questions/:question_id/answers/:id/edit(.:format) answers#edit
question_answer GET /questions/:question_id/answers/:id(.:format) answers#show
PATCH /questions/:question_id/answers/:id(.:format) answers#update
PUT /questions/:question_id/answers/:id(.:format) answers#update
DELETE /questions/:question_id/answers/:id(.:format) answers#destroy
questions GET /questions(.:format) questions#index
POST /questions(.:format) questions#create
new_question GET /questions/new(.:format) questions#new
edit_question GET /questions/:id/edit(.:format) questions#edit
question GET /questions/:id(.:format) questions#show
PATCH /questions/:id(.:format) questions#update
PUT /questions/:id(.:format) questions#update
DELETE /questions/:id(.:format) questions#destroy
Railsでリンクパスを生成する方法
XXX_path 方式
初心者的には一番最初に出会う王道的パスの生成方法
上記 rake routes
で出てきた Prefix を XXX に入れれば良い。
例: Question#showへのパス
question GET /questions/:id(.:format) questions#show
なので question_path :idがあるのでオブジェクトを引数に渡す
= link_to @question.title, question_path(@question)
Rails consoleで合ってるか確認
$ ./bin/rails c
pry> @question = Question.first
pry> app.question_path(@question)
=> "/questions/1"
ネストしてる場合
例: Answer#showへのパス
question_answer GET /questions/:question_id/answers/:id(.:format) answers#show
%ul
- @question.answers.each do |answer|
%li= link_to answer.id, question_answer_path(@question, answer)
Rails consoleで合ってるか確認
$ ./bin/rails c
pry> @question = Question.first
pry> answer = @question.answers.first
pry> app.question_answer_path(@question, answer)
=> "/questions/1/answers/1"
polymorphic_path 方式
モデルから該当のパスをジェネレートさせる方法 polymorphic_path で書きなおしてみる。
= link_to @question.title, @question
モデルから類推してちゃんとパスを生成してくれる。
Rails consoleで合ってるか確認
appにいきなりオブジェクトを渡してもダメなので、consoleでは明示的に polymorphic_path
と書く。
$ ./bin/rails c
pry> @question = Question.first
pry> app.polymorphic_path(@question)
=> "/questions/1"
ネストしてる場合
polymorphic_path で複数モデルを渡す場合、配列として渡す。
%ul
- @question.answers.each do |answer|
%li= link_to @answer.id, [ @question, answer ]
Rails consoleで合ってるか確認
$ ./bin/rails c
pry> @question = Question.first
pry> answer = @question.answers.first
pry> app.polymorphic_path([@question, answer])
=> "/questions/1/answers/1"
配列で渡さないと ArgumentError : wrong number of arguments (1 for 0)
になってしまう。
モデルが不要なパスを polymorphic_url で生成する方法
newとかindexみたいに、モデルが不要な場合
XXX_path方式
= link_to '新しく質問する', new_question_path
polymorphic_path 方式
シンボルで指定する。
以下の3つの方法は、どれも同じパスを生成できる。
= link_to '新しく質問する', [ :new, :question ]
= link_to '新しく質問する', polymorphic_path([ :new, :question ])
= link_to '新しく質問する', new_polymorphic_path(:question)
ネストしてる場合
= link_to '新しく回答する', [ :new, @question, :answer ]
= link_to '新しく回答する', polymorphic_path([ :new, @question, :answer ])
= link_to '新しく回答する', new_polymorphic_path([ @question, :answer ])