Creating a RESTful admin section in Rails.
Create an admin section using a single controller yet giving illusion of 2. Enough talk, let’s code! For those who love to follow along without typing you can pick up the project here. For those who like to type-along… let’s go. Remember, I use sqlite3 because it’s pretty disposable. You are welcome to use whatever you want. Also, we’re going to be using Rails 1.2.2 on Ruby 1.8.5 if you’re curious.
rails product_factory -d sqlite3
Ok, so all we’re going to do… I know, it’s so useless but this is more about the concept than anything truly functional… is create a Product! At the moment we’re going to add the user authorization but I’ll show you where it goes just in case. So, let’s get going…
script/generate resource product name:string description:text rake db:migrate
Ok, so here we’ve created the product resource and we’ve added the schema to the database. Now, let’s crack open the routes.rb file and do some tweeking. If you’d like, you can use the scaffold_resource generator. It does the same thing but also creates the views and stuff for you so you don’t have to add them manually, like I plan to do. :) Either way is fine. Ok, back to routes.rb
map.resource :admin do |admin|
admin.resources :products, :name_prefix => 'admin_'
end
map.resources :products
ok, so what have we done? We’re really only added a named route for our product resource that allows us to call at it in 2 ways…
/product/
or
/admin/product/
Both will work but the other thing that (:name_prefix=>’admin_’) does is it gives us the URL helper so that we can call out not only…
products_path (et all...)
but
admin_products_path (et all...) :)
as well. And they all point to the same controllers. Since this example assumes that it’s all still one resource and that an authenticated user can edit, update and delete and a regular user can only view, we’re on the right path. So, now that we’ve done some stuff, why not open or create index.rhtml under the products directory and see this in action. Throw this in there, fire up mongrel and open up http://localhost:3000/products.
products_url: <%= link_to products_path,products_path %><br> admin_products_url: <%= link_to admin_products_path,admin_products_path %>
now, click the links and what do you notice? Nothing! No difference, we’re pointing to the same resource. So, check if they are an authorized user and show them some stuff, right? Sweet, how about a different layout altogether? In the layouts directory, create 2 files “admin.rhtml” and “application.rhtml”. You can dress them up however you like, but all I have done for now, it to throw an H1 element in each telling me where I am and the call to yield. like so…
<h1>Hello regular person</h1> <%= yield %>
AND
<h1>Hello admin person</h1> <%= yield %>
and I add this little ditty to my product controller.
layout proc{ |r| (r.request.request_uri.index(/admin/) != nil) ? "admin" : "application" }
Now, remember, this is NOT what you’d want to do! You’re going to be authenticating users and at this point you’d want to write logic to swap the layout based on the logged in user and not if they have the word admin in the url. This is JUST for proof of concept. Ok, now that you’ve been warned let’s fire open a browser and look at what we’ve got.
You should be able to click the links and see the different (albeit pretty lame…) layouts using the same view and controller. Awesome-tastic or what?
In part 2 we’ll cover the same concept but using 2 controllers! You know, just in case you need it! :) Thanks again to John for having the issue that created the need for this article. :)
As always you can find the project here.
articleStats
Here are some silly little facts about this Creating a RESTful admin section in Rails....
article Links
These are the links that appear in this article. They probably don't make sense out of context... but just in case. :)
project here.Rails
you can find the project here.
Sweet.
Curious, which makes more sense -- one controller or two? It seems like you'd be wiring in a lot of conditionals and such to differentiate between the two intended targets in the one-controller version ... maybe I'm off on that thinking.
Oh well, I'll just hang around for that second article that'll prolly clear it all up for me. ;)