Main menu

Post navigation

Beginners Tutorial: Routing in Rails 2.0 (with REST) – Part 2 of n

Thank you to all of you who took the time to give me feedback on part 1. Most of the feedback was positive. A friend of mine suggested that I drop the sound effects and stick to the subject matter, I graciously accepted his advice. Therefore this post should have a better fact to fluff ratio than the previous one. On that note, let’s begin…

Part 2

In part 1 we learnt that the routing system has two main functions:
• Interpreting a request URL
• Generating a request URL
Rails uses the same routing rule to interpret a URL and to generate a URL.
Note that routing rules are often called routes, I will use the terms interchangeably.

Now we will start fixing our music_store application from part 1.

Experiment 2.1 – Setting up the ‘empty route’ to recognise and generate a default page

Please set your system environment up so that we can continue from where we left of at the end of part 1. Make sure the web server is running.

The aim of this experiment if to set the app\views\albums\index.html.erb page as the ‘default page’. Think of this as defining a type of welcome page. Do not confuse this notion of setting a default page with the default route – these ideas are very different, the default route will be discussed in another post.

Rails sidetrack: By default controllers render the view that has the same name of the action invoked. If we call the index action (method) on the albums_controller, it will render the view named index.html.erb in the app\views\albums folder. Similarly calling the show action will result in the show.html.erb view being rendered.

The index page will be shown if we can get Rails to instantiate an albums_controller and then invoke the index action on it. What we want to say is something like:

If we say this, there will be a problem when we deploy our application. We would then have to replace localhost with our sites domain name. To avoid this we can assume an implicit domain name. Therefore when defining routes we do not include our applications domain. Instead of saying http://localhost:3000/Albums we could simply say Albums. Similarly, we don’t use http://localhost:3000/, instead we use ‘’. This (‘’) is called the empty URL.

Side note: The term URL can refer to the fully qualified URL or just the path from after the root domain, it depends on the context.

Rails is pretty smart, therefore we use “albums” instead of “albums_controller”.
Taking one step closer to the actual code we get

Rails, when you get ‘’
:controller => “albums”
:action => “index”

The last two lines are (just about) lines of Ruby code. That is the Ruby code which forms part of the Rails DSL for defining routing rules. What we have just defined are referred to as the bounded parameters e.g. (:controller => “albums_controller”, :action => “index”).

To complete our route definition we need to connect the empty URL to the bounded parameters. This is how that is done in the config\routs.rb file:

Caution: Do not expect the music_store site to work now, there is more work to be done before it is fixed.

Let’s neaten up our Ruby code:

We have a method call on the map object which has two parameters, a string and a hash table.
We can get rid of the outer brackets because Ruby does not require them.
As the hash table is the last parameter; Ruby does not require the curly braces.
Now we have this clean version

:map.connect '', :controller => "albums", :action => "index"

Fire up the IRB to see if our route is there (we did this in part one).

This is what we are looking at:
ANY – this means it does not matter if the request is a GET or a POST
/ – This is the root domain (the empty URL)
{:action=>”index”, :controller=>”albums”} – Shows which controller and action is connected to the URL.

Read it like this: When an empty URL is received the index action will be called on the albums controller.

As you may recall, the routing system has two main functions. These are interpreting a URL and generating a URL. It does this using the routes defined within the routes.rb file. We will now use the IRB to interpret and generate URLs.

Start up the IRB; if you are not in it already.
Note your Rails server should also be running at this point.

Notice that the routing system uses the first rule that matches. You should be aware of this. Let’s assume we would rather have the routing system generate a URL with the music prefix. Swap the order of the routes:

Once again, don’t expect the actual music_store site to work just yet.

Experiment 2.3. Define routes for Add, Show, Edit & Delete

To get our site fixed, we also need to have routes that will allow us to add, show, edit and delete albums. Let’s start with showing a single album.

Show

We want to define a route that will instantiate the albums controller and call the show method. Looking at app\controllers\albums_controller we notice that the show action retrieves an :id field from the params hash table:

Thanks to Rails the params hash table is automatically available to the controller. We just need to make sure the route sets it. Let’s make our route say something like:Rails, when you get ‘music/show’
Instantiate controller “albums”
Invoke action “show”
Add a value to the params hash table with the key being :id and the value being …?

At this stage we do not know which album to show. We can add this to the URL.

Rails, when you get ‘music/show/3’
Instantiate controller “albums”
Invoke action “show”
Add a value to the params hash table with the key being :id and the value being 3

The :id symbol is used to pass through the album ID into the albums controller. We could use any symbol, as long as we were consistent in the controller. :id is a convention. :controller and :action must be used, they are the ingredients of some the Rails magic!Next we will delete or destroy an album.
Delete\Destroy

Now we want to say:Rails, when you get ‘music/delete/3’
Instantiate controller “albums”
Invoke action “destroy”
Add a value to the params hash table with the key being :id and the value being 3

It is very similar to show. Next up we define a route to Edit an album.

EditEdit is a two phase process. First we call edit on the controller, this will result in the album being shown. When the user clicks update we will call the update action on the controller. Therefore we need two routes to do an edit. Update your routes.rb file:

To add a new album is very similar to editing an existing album. It is a two phase process. First we call the new action on the albums controller, this will result in the new view being shown the user, this is an a form with empty fields. Once the user has completed the form the user clicks create. At this stage we want to call the albums controller invoking the create action.Edit the routes.rb file to look like this:

Delete the music_store\public\index.html page. Refresh your browser and you should see this error:

When using RESTful routing, and named routes, certain helper methods are dynamically generated. The methods are available to the controller and view. When Rails 2.0 performs scaffolding it assumes you are going to use RESTfull routing and therefore the view makes use of these helper methods. The music_store is currently not using named routes, or RESTful routes, therefore the helper methods are not available. Therefore we get the error message: “Undefined method ‘album_path’.

We can not see the helper method ‘album_path’ as it is being called implicitly by the link to method on line 13, it is Rails magic. If we had to remove this line we would end up with more errors. Remove line 13 and you will get the following error:Replace line 13 (if you removed it), your view should be back to this:

Looking at the view we can see multiple lines where Rails is using RESTful routing methods e.g. edit_album_path(album), new_album_path etc. These are the helper methods that would have been dynamically created had we been using RESTful routes. We are not and therefore we need to explicitly define our own paths.Update your app\views\albums\index.html.erb to look like this:

Unfortunately there is still more troubleshooting to be done. If you click on a link, you should find your application crashes. This is due to Rails using RESTfull calls throughout. Make the albums show.html.erb look like this:

Congratulations! The site is back up and running, and you still managed to provide two-nines of uptime 8)

A special thanks to Bill Thayer for notifying me of problems in this post. These issues have all been resolved. Please let me know if you encountered any problems…

The End of Part 2

That wraps things up for part 2. Amongst other topics, part 3 will cover the default route, receptors, named routes and finally RESTful routing. Once again these posts are on a demand bases. If this helped you and you would like another post, let me know. Feel free to let me know if there is something specific you would like me to cover.

Well, i really found this to be a very good guide to rails 2.0 routing,
since i created some stuff using scaffold and couldn’t understand why
it wouldnt find an action called ‘list’ an kept trying to use the show function with ‘list’ as its id. Anyway i really am looking forward to part 3 to get to know better about restful routing since it spares a lot of trouble. Keep up the good work and thanks!

At least not for this part, I explain will that ‘default route’ in part 3. That may have fixed your app, but I think you skipped a step in the tutorial. Are you sure you entered all the routes?

Thanks for the second point, I think my versions have been mixed up. The formatting was killing me with this post. I will update the tutorial over the weekend. I will post another comment confirming the fix.

Thank you! you saved my life, still learning the changes introduced with rails 2.0! great job, a thing, when using your html code tags there are some characters that you can’t type directly, instead use the html code for that, in my case using blogger all my code crash when im use the ‘.

What i recommend you is, try to catch the character that’s giving problems to you, and then before post, find and replace the character with the html code, blogger has problems with the less than character.

Thank you for this great tutorial. Even though I got stuck half way through part 2 I now have a little more insight into what is going on behind the scenes.

About a little more than half way on this page you say, “Now you should be able to see the albums index page in the browser!” but I cannot. I just read Goldberg’s comment and tried his fixes and still cannot see the index.html.erb in my browser.

Back again
After working on your post 2.. I was able to work out what you where trying to tell us.
Using one of my projects I added a controller with a few methods.
Changed the routes file similar to your “music” concept.
Spread a few link_to’s around to suit.

And it all worked….. OOOOOH What a Feeeeeeelling…

But alas
will need your next instalment to work out the way it is done in rails 2

I have gone through the part 2 and re-posted all the code. Most of the formatting and other errors are now fixed. Therefore I removed some of the comments, as they were no longer relevant.

I found that if you follow the instructions you will get it working. I did suffer from one glitch while working on this update, so I fear there may still be a problem, although I seriously doubt it. Then again, with code it is best to expect the unexpected…

Let me know if you successfully completed the part 2 tutorial after the date\time of this comment. And please le me know if something did not work.

Great works. I’ve been working with Rails for the last three months but with version 1.2.6 and last week one of my colleagues sent me an application to debug. When I realized he was using RESTful routing I was lost. Fortunately I found your blog and it has helped me a lot to understand RESTful routing.

Can’t wait for t3! My current app was built from generating scaffolding for all the models, and all the little simple ones update fine, but the workhorse controller when trying to update after doing an edit results in “Unknown action No action responded to 2” (where 2 was the id of the record being edited)

Thanks to your previous 2 tutorials, I’ve scoured my routes.rb and played in IRB and everything looks like it should work fine (and does for the simple models and their controllers). This is going to be one of those simple bang-head things when I find it!

Thanks very much for these tutorials!
I’m just beginning Rails and Part 1 of this tutorial series i followed without any problems.
Now in experiment 2.1 i added this to the routes.rb :
map.root :controller => “albums”, :action => “index”
I get the error::NameError: undefined local variable or method `“albums”’ for main:Object
I’m running rails 2.1.
Does anyone have an idea what i’m doing wrong here?
Thanks,
Mark

My question is: Should I then repeat this same line 5 times to map all
the other actions? That without counting the member actions? It
seems to me that when using map.resources there’s no way of taking the
controller name out of there. I think the only way is mapping each
routes independently, which is a long and tedious thing to do.