Disclaimer: first month of developing with rails, but I have read everything I could find.
Edit: Somehow I missed this very similar question with a similar final answer.
I have polymorphic flags:
Class Flag...
belongs_to :flaggable, :polymorphic => true
...
end
I have nested resources that have the appropriate has_many :flags, :as => :flaggable statement.
resources :posts do
resources :comments
end
I would like both posts and comments and in the future other things on the site to be flaggable. What is the DRY/standard way (I’m using Rails 3.1) to do this with regard to routes and controller?
What I did for routes:
Mostly based on this rails cast, I made flags as a nested resource of both posts and comments. Already, I think I’m on the wrong track because it seems to be re-stating the polymorphic relationships in the models as well as breaking the guideline that “Resources should never be nested more than 1 level deep.”
resources :posts do
resources :flags
resources :comments do
resources :flags
end
end
Alternatively, I thought to implement the flaggable routes separately as below. But again, this doesn’t seem DRY and additionally makes non-desired independent routes for comments.
resources :posts do
resources :flags
end
resources :comments do
resources :flags
end
Finally, I wondered if I could make a generic resource for flaggables. I couldn’t find any way to implement this and it has the same problem of the previous method of making general routes available for the generic flaggable type.
resources :flaggable do
resources :flags
end
What I did for the controller for the nested resources above:
I implemented find_flaggable, but realized that with nested resources, the parameter that gets converted to a flaggable class could be either Post or Comment since both end up in parameters (post_id and comment_id). I could solve the below with an id priority list for the current setup, but that is not a general solution and makes it even less DRY than it already is.
def find_flaggable
params.each do |name, value|
if name =~ /(.+)_id$/
return $1.classify.constantize.find(value)
end
end
nil
end
So this is where I stopped (actually implemented a limited solution only for Posts and Comments) and realized I don’t know a satisfying way to accomplish this. Can anyone help?
Just to solve the bit of DRYing up the code in your routes, a simple way would be to use
instead of
This starts becoming really clean and useful when you have a lot of actions under your nested resources. Sort of like a simple version of the “Extract method” refactoring for your routes.
EDIT
In case you missed my comment, I think polymorphic_url is the right thing you are looking for!!