Using polymorphic paths with nested associations

2020-05-19 07:28发布

问题:

I have a polymorphic association that looks like this:

class Line < ActiveRecord::Base
   belongs_to :item, :polymorphic => true
end

class Education < ActiveRecord::base
   has_many :lines, :as => :item
end

class Work < ActiveRecord::base
   has_many :lines, :as => :item
end

I'd like a simple way to create a new Line from the parent Item. So, I might be editing a view for a Work object, and want to have a link that creates a new Line object. Normally, I would do this:

<%= link_to "New Line", new_work_line_path(@work) %>

And the helper would work the route for this. However, this requires that I check which parent the Line belongs to in the controller, defeating the purpose of polymorphism (I could have used two references if that were the case). So, my question is, how do I get the path to work polymorphically like a normal path helper?

回答1:

A possible way could be to use routes like this:

map.resources :works do |works|
  works.resources :lines
end

map.resources :educations do |edu|
  edu.resources :lines
end

Your LinesController remains the same, and you'll get routes like these:

work_lines GET    /works/:work_id/lines
....
education_lines GET    /educations/:education_id/lines
...

The most annoying part is to manage the first id passed, because you'll have a params[:id] referred to a Line, but you'll also have params[:work_id] or params[:education_id]. Here you must choose between checking which param is passed, or at least parse the requested url to determine in which you are (Works, Educations, etc...).

Hope this helped ;)

EDIT:

According to what emerged in comments, you can use polymorphic_url/polymorphic_path (http://api.rubyonrails.org/classes/ActionDispatch/Routing/PolymorphicRoutes.html):

It makes sense if you use them like this way:

link_to "New Line", polymorphic_url(@line.item,@line)
# => /<educations_or_works>/item_id/lines/line_id

At least, you can even use it for collections:

link_to "New Line", polymorphic_url(@line.item,Line.new)
# => /<educations_or_works>/item_id/lines/

Cheers,
a.