Using a singleton resource for an admin section
Applications with an admin section often have a URL like http://myapp.com/admin, with that URL being a summary page, and all the other admin pages be under that URL (like, http://myapp.com/admin/users to edit users.). Without defining a lot of routes, this hasn’t been very easy with Rails…until now. Singleton resources have been merged into the 1.2 branch from edge-rails, so I thought I would share a little pattern that I’ve been using in several of my apps to accomplish this.
Singleton resources are like regular resources in Rails 1.2, except that they don’t have an :id parameter. This happens to work perfectly for using one controller to show a summary page, and then nesting the routes for other controllers inside of it.
The routes definition looks like this:
map.resource :admin do |admin|
admin.resources :users
end
Update: The key here is
map.resource(singular).
To make this work, generate an admin controller:
script/generate controller admin
You can now set up the “show” action in the admin controller to display a summary page.
The named route users_path now generates the URL /admin/users.
13 comments
Typo spotted :)
Should beAlso, isn’t this just Nested Resources which has been in edge for quite some time now?
Or has there been some great new change that I am failing to see?
Nevermind I get it now, you can delete the previous 2 comments :)
I wonder if this could have been done previously using something like
Probably not, but I might try it out for educational purposes.
If users_path generates /admin/users, how would you generate a users path outside of the context of the admin interface?
For instance, let’s say you wanted to display a list of all your users at: /users [GET].
Just use a name_prefix like so
That will allow you to do users_path normally, and then admin_users_path as well.
Justin: re: using path_prefix. Yes, but the main issue is getting /admin to show a summary. That’s what I’ve never been able to accomplish before without using a ton of routes.
Shalev: the other thing I do often with this pattern is use 2 different controllers for the frontend and backend:
map.resources :users map.resource :admin do |admin| map.resources :users, :name_prefix => 'admin_', :controller => 'admin/users' endHaving 2 controllers for the same model used to bother me, but once I started doing it, it made things a lot easier and cleaner.
Ahh, that makes a lot of sense. You’re right though, having two controllers for one model is a bit of a paradigm shift in Rails (despite this being the point of MVC in the first place).
I assume that you do this when the range of actions for a normal user and an admin are sufficiently different? For instance, editing a user is a normal action that is usually constrained to a user editing themselves. An admin editing another user would just be a quick before_filter or flag and wouldn’t really require an entire new controller.
Shalev,
Yeah, if it’s something as simple as a before filter, then I would do that. But usually it’s more complicated than that. In the apps that I’m using this pattern, the admin interface has different rules and provides access to more. I could just put a bunch of if statements in each action-
and I have done that before-but using separate actions has made it a lot cleaner and clearer.Re: Brandon Well, it’s quite simple really. Just use a specific named route (as opposed to a singular resource – old style)
That should work fine, but is obviously not as simple as the new singular resources you have pointed out.
Or maybe I am missing your point?
Brandon, I’m curious about what you name your two Controllers.
Would you name them say, Users and AdminUsers?
Then using route definitions like:
Justin,
I’ve been using namespaced controllers.
A tutorial on how you setup a basic admin with two controllers, routes from scratch would be great!
Nevertheless, this helped me fix the issue I was befuddled with, so thanks!
Speak your mind: