Automatically add parent model id in nested resources
With nested resource routes in Rails 3, such as the following:
resources :magazines do
resources :开发者_JAVA技巧ads
end
helpers such as magazine_ad_path
are defined, to which I have to pass both a magazine and the ad, which is inconvenient if I just have a reference to the ad:
magazine_ad_path(@ad.magazine, @ad)
Is there a nice way to set up an ad_path
helper that takes the @ad
and returns the appropriate address including the magazine ID? (This would also then allow the use of link_to @ad
, redirect_to @ad
, etc., which automatically call the ad_path
helper corresponding to the model class.)
Shallow Routing seems to be what you're looking for. You can implement shallow nesting as below :
resources :magazines do
shallow do
resources :ads
end
end
OR
resources :magazines, :shallow => true do
resources :ads
end
Only the index and the new actions are nested.
Using nested resources tends to generate long URLs, shallow nesting helps remove parts (that contain the parent resource route as well) that aren't necessarily required for certain actions(since a parent resource can be derived from a persisted child record).
One possible but ugly solution is:
module RoutesHelper
def ad_path(ad)
magazine_ad_path(ad.magazine, ad)
end
def ad_url(ad)
magazine_ad_url(ad.magazine, ad)
end
def edit_ad_path(ad)
edit_magazine_ad_path(ad.magazine, ad)
end
def edit_ad_url(ad)
edit_magazine_ad_url(ad.magazine, ad)
end
...
end
[ActionView::Base, ActionController::Base].each do |m|
m.module_eval { include RoutesHelper }
end
Unfortunately, this has the disadvantage that I have to define different helpers for _path
and _url
because redirect_to
uses the _url
helpers, I have to write the edit_
helpers manually (and maybe I'm missing some; not sure on that), and it's just plain ugly.
One solution i like to use in this case is to make the instance returning his own path, like this:
class Ad
def path action=nil
[action, magazine, self]
end
end
Then in your view you can use this array as a polymorphic route:
link_to @ad.path
link_to @ad.path(:edit)
Of course it also work with redirect_to, etc
精彩评论