Most of my clients prefer to have a separate admin section. In turn, I like to have separate controllers for admin section and front-end in my Rails app. This is not as straightforward as it might seem, especially if you like to use scaffolding for admin controller.
The goal is to get 2 separate RESTful controllers, admin & front-end controller, one model and for admin pages to have scaffolding.
Here is the easiest way I found so far to accomplish this. This example generates categories model and controllers for it.
./script/generate controller admin/categories
./script/generate scaffold category name:string
This will generate an empty controller in admin namespace and a scaffolded resource for front-end controller.
Now we have everything generated we just need to make it work with admin controller and not with front-end.
- move all templates from app/views/categories to app/views/admin/categories
- copy all functions from categories_controller.rb to admin/categories_controller.rb
- add namespace for admin controller in routes.rb:
map.namespace :admin do |admin|
admin.resources :categories
end - in admin/categories_controller.rb replace in 3 places redirect_to calls to work with admin namespace. It will have something like redirect_to(@category), but to work with namespace it needs to have redirect_to([:admin, @category])
- make similar changes in all templates, i.e. make it work within an admin namespace. You need to make following changes:
- form_for(@category) => form_for([:admin, @category])
- <%= link_to ‘Show’, @category %> => <%= link_to ‘Show’, [:admin, @category] %>
- categories_path => admin_categories_path
- edit_category_path(@category) => edit_admin_category_path(@category)
- new_category_path => new_admin_category_path
That’s it. Now you’ll have /admin/categories for all administrative tasks and you have a free controller for front-end actions.
You might wonder why not just generate scaffold for admin/categories… The reason is that you’ll also get a model that is namespaced in admin (i.e. model would be Admin::Category). Scaffolded views also wouldn’t work as it seems that generator doesn’t take into account the fact that you are using a namespace.
the following doesn’t work for me:
script/generate controller admin/categories
I’m doing script/generate controller user/accounts
and I get the error:
The name ‘user’ is either already used in your application or reserved by Ruby on Rails.
Please choose an alternative and run this generator again.
I would’ve expected this to generate an accounts_controller in the user namespace. I’m toying with the restful authentication framework, where this code has come from..
Now what about the functional tests? I was just messing with scaffolding today after being a long-time hand coding guy. It’s unfortunate you cannot just specify the namespace for the controller since this is such a common practice (especially for admin site as you noted).
Awesome!
Thank you
I’ve been playing with this for a couple of days now and have found that it works perfectly for the scaffolded and model based routes.
I am totally hooked on this solution but I am struggling with non model based routes.
for example a generated admin/home controller on it’s own does not seem to like routes for link_to commands
If I am trying to render a non model view with a link_to command I would normally use the :controller parameter. As this controller is now in an admin folder I’m faced with calling
link_to(”Administration”, :controller => ‘admin/home’)
Whilst this works it doesn’t ‘feel’ very restful and was wondering if you handle this scenario differently?
Thanks
James
I don’t think that there another way. That’s the only way to reference namespaced controller.
Good trick Slobo! Sadly there’s no other way.
Thank you so much. Exactly the information I needed, not that pretty but now I can do what I want to achieve.
This was exactly what I was looking for. Thank you for making this info available…I’d have never figured out the wonky namespace head-standing/hair-pulling required in the views.
Thanks!
( I await the day I can script/generate scaffold Namespace::Thing, tho and have the models “work” and the resources “work” )
[...] an admin area to do all the backend stuff to manage all your content and users. [icebergist] gives one way of adding an admin area to your web [...]
Thank you very much, you saved my life! =D
I was trying all day to make this work and this post was exactly what I was looking for! I’m new to Ruby on Rails so i’m still getting how it really works… thk u very much!
Thanks for the really helpful code. I’m trying to do this operation with admin and users (rather than categories) but getting a path error.
The links in my admin/users index.html.erb page are causing errors. For example, the first “show” link is causing an “undefined method `admin_path’ for
Here’s the offending code on my index.html.erb
‘Are you sure?’, :method => :delete
I have the following in my routes….
map.namespace :admin do |admin|
admin.resources :users
end
Any thoughts on what I’ve done wrong? Thanks in advance for any help or suggestions!
Daniel
…arrrgh, the code got cut out. Here’s the problematic code:
‘Are you sure?’, :method => :delete %>
…[head thumps against wall]…
link_to “Show”, [:admin, @user]
link_to “Edit”, edit_admin_user_path(@user)
link_to “Destroy”, user, :confirm => ‘Are you sure?’, :method => :delete
Do you think it’d be possible for you to teach us how to password protect the admin namespace?
Zak, to “protect the namespace” you actually need to limit access to each controller (their actions to be precise) within that namespace. Usually you will add some before_filters that will handle authorization. Something like this:
before_filter :admin_only
Exact way to do this varies depending on what you use (if any) as an user system. For example, if you use Clearance you can do like this: http://wiki.github.com/thoughtbot/clearance/admin
Thanks Slobodan, it’s a very useful tutorial. I have a one question: is it exists some newer solution? I ask you because this was posted on September 2008.
Greetings from Poland
@Daniel the destroy link should use the [:admin, user] notation.
link_to ‘Destroy’, [:admin, theme], :confirm => ‘Are you sure?’, :method => :delete