Rails Namespace vs. Nested Resource
Solution 1
I think what you're trying to achieve is:
- Bar has many Foos
- View Foos belonging to Bar
- View all Foos regardless of parent.
You can achieve that with: routes.rb:
resources :foos
resources :bars do
resources :foos, :controller => 'bars/foos'
end
The route helpers you end up with are:
- bars_path
- foos_path
- bars_foos_path
- etc, etc, 'rake routes' for the rest =)
In essence, you end up with:
- app/BarsController (rails g controller bars)
- app/FoosController (rails g controller foos)
- app/bars/FoosController (rails g controller bars/foos)
In FoosController, you would access foos as usual with:
@foos = Foos.all
and in bars/FoosController, you would access bar's foos with:
@foos = @bar.foos
where bar can be pre-retrieved in the bars/foos controller with:
before_filter :get_client
private
def get_client
@bar = Bar.find(params[:bar_id])
end
Hope this helps. =)
Edit: As for namespaced routes, I've personally used them when I some of my resources retrieved from a sub-path. For example, if I have an admin section of my site, then I might have the following:
routes.rb:
namespace :admin do
resources :foos
end
and I create my controller with:
rails g controller admin/foos
This sets up my foos resource, such that I can access it at "my site url"/admin/foos, and also get helpers such as admin_foos_path.
Solution 2
There are cons to this approach.
If you declare a constant, eg. CONST_NAME, in nested resource foos
, rails will throw "uninitialized constant ::Foo::CONST_NAME" exception because of its scope algorithm.
To avoid such behaviour, use:
resources :foos
resources :bars do
scope :module => "bar" do
resources :foos #, :controller => 'bar/foos' no need to use this now because route will be searched there by default
end
end
Now you will not get an exception while using:
Foo::CONST_NAME
or
Bar::Foo::CONST_NAME
Comments
-
Andrew almost 2 years
Let's say my app has two models, Foo and Bar.
Foo optionally belongs_to Bar.
Right now I can look at a single Foo, or search for a particular Foo, and the FoosController handles all that. My URLS are like:
foos/1
andfoos/new
Sometimes I want to look at a Bar. The BarsController handles that, and I get to it like:
bars/1
orbars/1/edit
.If I'm looking at a Bar I might want to browse all the Foos that are part of that Bar. So, I'd like to use
bars/1/foos/
to look at those Foos.This is pretty straightforward with nested resources, and it looks like this:
resources :foo resources :bar do resources :foo end
However, Foos that are part of a Bar are kind of special, set apart from regular Foos. So, for instance, if I load
foos/1
orbars/1/foos/1
, I would be looking at the same Foo, but I am focused on different information in each case.So I've been thinking about having a BarFoos Controller to handle Foos when they're in the context of a Bar. However, if I nest BarFoos under Bar, then my helpers are going to be like
bar_bar_foos_path
andnew_bar_bar_foo_path
. That seems redundant.So, now I'm thinking about namespaces, which is something I've never looked into before. I see in the rails guide that I could define:
namespace "bar" do resources :foos end
If I do that I can make a second
FoosController
underapp/bar/
, and that FoosController can handle Foos inside of a Bar with nice helpers likebar_foo_path(:id)
instead ofbar_bar_foo_path(:id)
.But if I do that, what happens to my
BarsController
? How do requests get routed toBarsController
if instead ofresources :bars
I havenamespace "bar"
?And, lastly, is there anything special I need to do inside my secondary FoosController to make sure there's not a name conflict with the top-level FoosController? I realize the routing says "namespace", but how does the rest of the ruby code know that the
app/bar/foos_controller
andapp/foos_controller
are not the same class?Thanks!