Search code examples
ruby-on-railsruby-on-rails-3routesnested-resources

Combining shallow and non-shallow routes on a single Rails resource


Let's say I have a Magazine model and Ad model, such that Magazine :has_many => :ads. I have setup my nested resource routing as follows:

resources :magazines do 
  resources :ads, :shallow => true do
    get 'search', :action => :search, :on => :collection
  end
end

My goal here is to be able to access the default CRUD routes created by Rails resources, plus a search route, on both a nested and shallow level. I want the user to be able to restrict his search from within the context of a given Magazine, or search all Ads regardless of parent Magazine, because some Ads won't have parent Magazines. In other words, I want to be able to:

/magazines/1/ads/new
/ads/new

/magazines/1/ads/search
/ads/search

# ... all standard CRUD routes ...

My concern is that the path variables in the views rely on things like new_magazine_ad_path(@magazine). Won't accessing a route like /ads/index (which should contain a link to create a new ad) break on encountering the new_magazine_ad_path(@magazine) helper without any @magazine instance to guide it?


P.S.: Normally, I would try all this out myself to see what worked, but I'm stuck right now with the above setup - I can only reach the edit, delete, show, and update shallow routes:

/ads/:id
/ads/:id/edit
/ads/:id (put)
/ads/:id (delete)

and no new or index routes:

/ads/index
/ads/new

Update

So Shreyas proposed creating two controllers, one to handle the nested Ad, and one to handle the shallow Ad. This makes sense, but it leaves me duplicating all the view code just to change the path helpers from magazine_ad_path(@magazine) to ad_path. Any ideas on a DRY'er approach to handling the view changes? All the other view code is identical.


Solution

  • I want the user to be able to restrict his search from within the context of a given Magazine, or search all Ads regardless of parent Magazine, because some Ads won't have parent Magazines

    You have two different concerns here. I would suggest you have two different controllers for the two concerns. One of course which comes under the Magazine context and the other as a stand-alone controller (an AD that does not have a parent magazine).

    This way you have two different controllers with clearly separated concerns.

    resources :ads do
      get 'search', :action => :search, :on => :collection
    end
    resources :magazines do 
      resources :ads, :shallow => true do
        get 'search', :action => :search, :on => :collection
      end
    end