Apr 06, 2010 @ 11:09 am

You want a RESTful Rails app with a backend administration? The worst thing to do in my opinion is to use the same controllers for the public and the admin side. At first, it might look wise to do this. I mean, if you have a “books” resource, it would be logical that all methods related to books go in the same controller, right? Well, logical or not… I suggest you never do this because your application will become a real mess in no time. Personally, I did it once and will never get caught again!

Exemple of a mess in a controller :

def index
  if administrator?
    @books = Book.all
  else
    @books = Book.published
  end

Example of a mess in a view :

<%if administrator?%>
<%=render :partial => "admin_index"%>
<%else%>
&lt;h1&gt;Published books&lt;/h1&gt;
bla bla bla
<%end%>

If you go that route, be prepared to make your fingers bleed because you will write tons of confusing and ugly “if” statements everywhere. Most of the time anyway, what you need to do with the resources is completely different depending if you’re on the admin or public side, so you’re better to separate them.

Step #1 : Generating the controllers
To generate a public controller, you do like you always do : ./script/generate controller books

To generate its admin counterpart, you simply do this : ./script/generate controller admin/books

Rails will generate the controller in controllers/admin/books_controller.rb and a folder for the views in views/admin/books

Step #2 : Configuring the routes
One route for the public side :

map.resources :books, :only => [:index, :show]

One route for the admin side

map.namespace :admin do |admin|
  admin.resources :books
  admin.resources :some_other_resource
end

Now your namespaced controller has its own named urls as well : admin_books_url, edit_admin_book_url and so on…

Step #3 : Get the “form_for” url right

<%form_for [:admin, @book] do |f|%>
   <%=f.text_field :title%>
   <%=f.submit "Save"%>
<%end%>

That way Rails will correctly call the update/create method in controllers/admin/books_controller.rb instead of the one in controllers/books_controller.rb

A final note
The controllers and the views are best kept separated but NOT the model which should always remain unique in your app.

Bookmark this post : These icons link to social bookmarking sites where readers can share and discover new web pages.
  • DZone
  • Reddit
  • del.icio.us
  • Digg
  • Furl
  • Technorati
  • StumbleUpon
Posted under : short & sweet
10 Comments

I was just trying to figure out the form_for part yesterday. Thank you!

Comment by : JanNo Gravatar
— April 6, 2010 @ 2:23 pm

@Jan,

Yeah this thing with the form_for helper is not obvious at all IMO. I’m glad it was helpful to you!

Comment by : FrankNo Gravatar
— April 6, 2010 @ 2:42 pm

while I do mostly agree with you, your exampled reasoning could be resolved with something like this

http://gist.github.com/357973

Comment by : mike wyattNo Gravatar
— April 6, 2010 @ 3:24 pm

@mike wyatt

Yes, this is without a doubt a more elegant way to fetch the resources. But what about before and after filters that must not be called when you’re on the admin side or the other way around? It means more conditionals expressions and more obstrusive code to write. And then there are the update and create actions that will differ and generate some “if” statements… and then there are the views, the partials… Exceptions start to popup everywhere and the nightmare begins!

Thanks for your code snippet though. I like how you made it generic and named the method “resources”. It keeps you thinking in REST mode.

Comment by : FrankNo Gravatar
— April 6, 2010 @ 3:38 pm

I have been using this technique for a while now on a very large app. I not only have admins and normal users, but some in between types. The namespacing works great to separate out these concerns. My only complaint with the technique is that views tend to not be dry, so sometimes a single UI change might require editing multiple views across all of the namespaces.

Comment by : Brandon HauffNo Gravatar
— April 7, 2010 @ 10:32 am

@Brandon Hauff

Very good point. But IMO it is a scenario where it’s ok to slack off with the DRY principle. It’s better to repeat a few things here and there with your views than to pollute your app with some ugly conditional statements.

Thanks for your comment!

Comment by : FrankNo Gravatar
— April 8, 2010 @ 12:01 am

It’s unbelievable how this post helped me in the last project I’m working on. I avoid complex structures of ifs everywhere… even if sometimes, I have to repeat myself, it’s much clearer.

Comment by : DanNo Gravatar
— April 23, 2010 @ 9:48 am

@Dan, glad that you found the post useful!

Instead of DRY, it should be TNRYBDBAAI : Try Not Repeating Yourself But Don’t Be Anal About It.

Comment by : FrankNo Gravatar
— April 23, 2010 @ 4:54 pm

PTSD Reference List (Alpha)…

I found your entry interesting thus I’ve added a Trackback to it on my weblog :)…

— June 18, 2010 @ 4:51 pm

Just to put my 2 cents in. Most of the time administrative views are completely different to what normal users see. Take WordPress for example, there’s little to no “repeating yourself”! But, if you don’t have a CMS then use partials.

Comment by : MaxNo Gravatar
— December 26, 2010 @ 2:43 pm




Leave a comment
Name (required)
Email (will not be publish) (required)
Website