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

Part 3

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:

Rails, when you get http://localhost:3000/
Instantiate controller “albums_controller”
Invoke action “index”

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.

Using the empty URL we can say something like:

Rails, when you get ‘’
Instantiate controller “albums_controller”
Invoke action “index”

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:

ActionController::Routing::Routes.draw do |map|
  map.connect('', {:controller => "albums", :action => "index"})
end

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).

C:\InstantRails-2.0-win\rails_apps\music_store>ruby script\console

Loading development environment (Rails 2.0.2)

>> rts = ActionController::Routing::Routes

--- output ---

>>

puts rts.routes

ANY    /              {:action=>"index", :controller=>"albums"}

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.

C:\InstantRails-2.0-win\rails_apps\music_store>ruby script\console

Loading development environment (Rails 2.0.2)

>> rts = ActionController::Routing::Routes

--- output ---

>> rts.recognize_path("/")

=> {:action=>"index", :controller=>"albums"}

>> rts.recognize_path("")

=> {:action=>"index", :controller=>"albums"}

This shows us how the routing system would interpret these URLs. We can see that “/” and “” are both interpreted the same – they are both the empty URL.

Now lets test the URL generation

>> rts.generate(:controller=>"albums",:action=>"index")

=> "/"

The routing system found where we had defined an albums controller and the index action, it then returned the connected URL – which was the empty URL.

This completes experiment 2.1. as we have defined a route that allows the routing system to generate and interpret an empty URL.

Note that the actual site will not work at this point. We still need to do some troubleshooting on the albums views, we will do that later.

Experiment 2.2. Explore route ordering

In order to explore route ordering, we need a second route. Let us assume we want to map the URL http://localhost:3000/Music to the same albums controller and index action.

Rails, when you get ‘/Music’
Instantiate controller “albums_controller”
Invoke action “index”

Update the routes.rb file to look like this:

ActionController::Routing::Routes.draw do |map|
  map.connect '', :controller => "albums", :action => "index"
  map.connect 'music', :controller => "albums", :action => "index"
end

Now inspect the behaviour of the routing system via the IRB:

C:\InstantRails-2.0-win\rails_apps\music_store>ruby script\console

Loading development environment (Rails 2.0.2)

>> rts = ActionController::Routing::Routes

-- output--

>>

puts rts.routesANY    /      {:action=>"index", :controller=>"albums"}

ANY    /music/                {:action=>"index", :controller=>"albums"}

=> nil

>>

Great, there is the new route. Note that our music URL does not match our folder structure. Therefore a user can not really tell the file structure of a Rails application from the URL.

Test recognize:

>> rts.recognize_path("")

=> {:action=>"index", :controller=>"albums"}

>> rts.recognize_path("/music")

=> {:action=>"index", :controller=>"albums"}

As expected! But now try a generate:

>> rts.generate(:controller=>"albums",:action=>"index")

=> "/"

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:

ActionController::Routing::Routes.draw do |map|

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

end

Now test generate again, remember to exit the IRB first.

?> exit

C:\InstantRails-2.0-win\rails_apps\music_store>ruby script\console

Loading development environment (Rails 2.0.2)

>> rts = ActionController::Routing::Routes

-- output --

>> rts.generate(:controller=>"albums",:action=>"index")

=> "/music"

>>

All good! Ordering explored, experiment completed!

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:

  def show
    @album = Album.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @album }

    end
  end

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

Update routes.rb to look like this:

ActionController::Routing::Routes.draw do |map|

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

  map.connect 'music/show/:id', :controller => "albums", :action => "show"

end

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

Add this to the routes.rb so that we have:

ActionController::Routing::Routes.draw do |map|

  map.connect 'music', :controller => "albums", :action => "index"
  map.connect '', :controller => "albums", :action => "index"
  map.connect 'music/show/:id', :controller => "albums", :action => "show"

  map.connect 'music/delete/:id', :controller => "albums", :action => "destroy"

end

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

Edit

Edit 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:

ActionController::Routing::Routes.draw do |map|

  map.connect 'music', :controller => "albums", :action => "index"
  map.connect '', :controller => "albums", :action => "index"
  map.connect 'music/show/:id', :controller => "albums", :action => "show"
  map.connect 'music/delete/:id', :controller => "albums", :action => "destroy"

  map.connect 'music/edit/:id', :controller => "albums", :action => "edit"
  map.connect 'music/update/:id', :controller => "albums", :action => "update"

end

Add

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:

ActionController::Routing::Routes.draw do |map|

  map.connect 'music', :controller => "albums", :action => "index"
  map.connect '', :controller => "albums", :action => "index"
  map.connect 'music/show/:id', :controller => "albums", :action => "show"
  map.connect 'music/delete/:id', :controller => "albums", :action => "destroy"
  map.connect 'music/edit/:id', :controller => "albums", :action => "edit"
  map.connect 'music/update/:id', :controller => "albums", :action => "update"

  map.connect 'music/new', :controller => "albums", :action => "new"
  map.connect 'music/create', :controller => "albums", :action => "create"

end

We are creating a new album, there is no need to pass in the :id field. Those are our basic routes.If you have kept up, Named routes and RESTful routing will be simple, a piece of PHP Cake!

Experiment 2.4. Troubleshooting

To get all of this to work in the browser, we need to perform some troubleshooting. As you may recall we set up a route that will show the albums index view if an empty URL is passed in.

To properly test the route, open your browser and navigate to http://localhost:3000/.

What’s this? Our old friend, the about your application window?

Welcome

To stop this from showing we need to delete this index page.

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

View Error 1

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’.

Open the app\views\albums\index.html.erb, it should look as follows:

<h1>Listing albums</h1>
<table>
<tr>
<th>Title</th>
<th>Review</th>
</tr>
<% for album in @albums %>
<tr>
<td><%=h album.title %></td>
<td><%=h album.review %></td>
<td><%= link_to 'Show', album %></td>
<td><%= link_to 'Edit', edit_album_path(album) %></td>
<td><%= link_to 'Destroy', album, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %></table>
<%= link_to 'New album', new_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:View Error 2Replace line 13 (if you removed it), your view should be back to this:

<h1>Listing albums</h1>
<table>
<tr>
<th>Title</th>
<th>Review</th>
</tr>
<% for album in @albums %>
<tr>
<td><%=h album.title %></td>
<td><%=h album.review %></td>
<td><%= link_to 'Show', album %></td>
<td><%= link_to 'Edit', edit_album_path(album) %></td>
<td><%= link_to 'Destroy', album, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %></table>
<%= link_to 'New album', new_album_path %>

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:

<h1>Listing albums</h1>
<table>
<tr>
<th>Title</th>
<th>Review</th>
</tr>
<% for album in @albums %>
<tr>
<td><%=h album.title %></td>
<td><%=h album.review %></td>
<td><%= link_to 'Show', :controller => "albums", :action => "show", :id => album.id  %></td>
<td><%= link_to 'Edit', :controller => "albums", :action => "edit", :id => album.id %></td>
<td><%= link_to 'Destroy', {:controller => "albums", :action => "destroy", :id => album.id}, :confirm => 'Are you sure?' %></td>
</tr>
<% end %></table>
<%= link_to 'New album', :controller => "albums", :action => "new" %>

Now you should be able to see the albums index page in the browser!
Either with: http://localhost:3000/music or http://localhost:3000/.

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:


  <b>Title:</b>
  <%=h @album.title %>

  <b>Review:</b>
  <%=h @album.review %>

<%= link_to 'Edit', :controller => "albums", :action => "edit", :id => @album.id %> |
<%= link_to 'Back', :controller => "albums", :action => "index" %>

You should be able to click show on the index view, and back on the show view.
The destroy\delete functionality will be fixed later on.

To fix the editing function we must alter the edit.html.erb and the controller. Make the edit view look like this:

<h1>Editing album</h1>
<%= error_messages_for :album %>

<% form_for :album, @album, :url => { :controller => "albums", :action => "update" } do |f| %>

    <b>Title</b>
    <%= f.text_field :title %>

    <b>Review</b>
    <%= f.text_area :review %>

    <%= f.submit "Update" %>

<% end %>

<%= link_to 'Show', :controller => "albums", :action => "show", :id => @album.id %> |
<%= link_to 'Back', :controller => "albums", :action => "index" %>

For help on form_for I recommend the Rails documentation.

Then edit the controllers update method:


class AlbumsController < ApplicationController
  # GET /albums
  # GET /albums.xml
  def index
    @albums = Album.find(:all)

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @albums }
    end
  end

  # GET /albums/1
  # GET /albums/1.xml
  def show
    @album = Album.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @album }
    end
  end

  # GET /albums/new
  # GET /albums/new.xml
  def new
    @album = Album.new

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @album }
    end
  end

  # GET /albums/1/edit
  def edit
    @album = Album.find(params[:id])
  end

  # POST /albums
  # POST /albums.xml
  def create
    @album = Album.new(params[:album])

    respond_to do |format|
      if @album.save
        flash[:notice] = 'Album was successfully created.'
        format.html { redirect_to(@album) }
        format.xml  { render :xml => @album, :status => :created, :location => @album }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @album.errors, :status => :unprocessable_entity }
      end
    end
  end

  # PUT /albums/1
  # PUT /albums/1.xml
  def update
     @album = Album.find(params[:id]) 

     respond_to do |format|
       if @album.update_attributes(params[:album])
         flash[:notice] = 'Album was successfully updated.'
         format.html { redirect_to(:controller => "albums", :action => "show", :id => @album.id) }
         format.xml  { head :ok }
       else
         format.html { render :action => "edit" }
         format.xml  { render :xml => @album.errors, :status => :unprocessable_entity }
       end
     end
   end  

  # DELETE /albums/1
  # DELETE /albums/1.xml
  def destroy
    @album = Album.find(params[:id])
    @album.destroy

    respond_to do |format|
      format.html { redirect_to(albums_url) }
      format.xml  { head :ok }
    end
  end
end

Now let’s fix the new functionality. As you might have guessed, this also takes two steps. The new new.html.erb:

<h1>New album</h1>
<%= error_messages_for :album %>

<% form_for :album, @album, :url => { :controller => "albums", :action => "create" } do |f| %>

    <b>Title</b>
    <%= f.text_field :title %>

    <b>Review</b>
    <%= f.text_area :review %>

    <%= f.submit "Create" %>

<% end %>

<%= link_to 'Back', :controller => "albums", :action => "index" %>

And update the Albums controller create method:


class AlbumsController < ApplicationController
  # GET /albums
  # GET /albums.xml
  def index
    @albums = Album.find(:all)

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @albums }
    end
  end

  # GET /albums/1
  # GET /albums/1.xml
  def show
    @album = Album.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @album }
    end
  end

  # GET /albums/new
  # GET /albums/new.xml
  def new
    @album = Album.new

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @album }
    end
  end

  # GET /albums/1/edit
  def edit
    @album = Album.find(params[:id])
  end

  # POST /albums
  # POST /albums.xml
  def create
     @album = Album.new(params[:album]) 

     respond_to do |format|
       if @album.save
         flash[:notice] = 'Album was successfully created.'
         format.html { redirect_to(:controller => "albums", :action => "show", :id => @album.id) }
         format.xml  { render :xml => @album, :status => :created, :location => @album }
       else
         format.html { render :action => "new" }
         format.xml  { render :xml => @album.errors, :status => :unprocessable_entity }
       end
     end
  end  

  # PUT /albums/1
  # PUT /albums/1.xml
  def update
     @album = Album.find(params[:id]) 

     respond_to do |format|
       if @album.update_attributes(params[:album])
         flash[:notice] = 'Album was successfully updated.'
         format.html { redirect_to(:controller => "albums", :action => "show", :id => @album.id) }
         format.xml  { head :ok }
       else
         format.html { render :action => "edit" }
         format.xml  { render :xml => @album.errors, :status => :unprocessable_entity }
       end
     end
   end  

  # DELETE /albums/1
  # DELETE /albums/1.xml
  def destroy
    @album = Album.find(params[:id])
    @album.destroy

    respond_to do |format|
      format.html { redirect_to(albums_url) }
      format.xml  { head :ok }
    end
  end
end

Finally update the destroy action in the the albums controller to look like this:


class AlbumsController < ApplicationController
  # GET /albums
  # GET /albums.xml
  def index
    @albums = Album.find(:all)

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @albums }
    end
  end

  # GET /albums/1
  # GET /albums/1.xml
  def show
    @album = Album.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @album }
    end
  end

  # GET /albums/new
  # GET /albums/new.xml
  def new
    @album = Album.new

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @album }
    end
  end

  # GET /albums/1/edit
  def edit
    @album = Album.find(params[:id])
  end

  # POST /albums
  # POST /albums.xml
  def create
     @album = Album.new(params[:album]) 

     respond_to do |format|
       if @album.save
         flash[:notice] = 'Album was successfully created.'
         format.html { redirect_to(:controller => "albums", :action => "show", :id => @album.id) }
         format.xml  { render :xml => @album, :status => :created, :location => @album }
       else
         format.html { render :action => "new" }
         format.xml  { render :xml => @album.errors, :status => :unprocessable_entity }
       end
     end
  end  

  # PUT /albums/1
  # PUT /albums/1.xml
  def update
     @album = Album.find(params[:id]) 

     respond_to do |format|
       if @album.update_attributes(params[:album])
         flash[:notice] = 'Album was successfully updated.'
         format.html { redirect_to(:controller => "albums", :action => "show", :id => @album.id) }
         format.xml  { head :ok }
       else
         format.html { render :action => "edit" }
         format.xml  { render :xml => @album.errors, :status => :unprocessable_entity }
       end
     end
   end  

  # DELETE /albums/1
  # DELETE /albums/1.xml
  def destroy
    @album = Album.find(params[:id])
    @album.destroy

    respond_to do |format|
      format.html { redirect_to( :controller => "albums", :action => "index" ) }
      format.xml  { head :ok }
    end
  end
end

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.

Thanks…

Part 3

About these ads

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

  1. Pingback: Beginners Tutorial: Routing in Rails 2.0 (with REST) - Part 1 of n « Daryn’s Blog

  2. Thanks to those of you who pointed out the formatting issues – This post has a mind of it’s own with regards to formatting.

    If you read this post before, the console lines may have been misleading as they were being cut in half. Sorry about that…

    I believe I fixed the problems, PLEASE let me know if something seems wrong. Thank you, Daryn

  3. 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!

  4. i keep getting this error when i open up the website. i’m sure that i did everything according to the tutorial.

    ActionController::RoutingError in Albums#index

    Showing albums/index.html.erb where line #13 raised:

    No route matches {:controller=>”albums”, :action=>”show”, :id=>1}

    Extracted source (around line #13):

    10:
    11:
    12:
    13: “albums”, :action => “show”, :id => album.id} %>
    14: “albums”, :action => “edit”, :id => album.id %>
    15: “albums”, :action => “destroy”, :id => album.id}, :confirm => ‘Are you sure?’ %>
    16:

    can anyone help me with this?

  5. i’ve just found out what i’ve done wrong.

    in the routes.rb, you still need:
    map.connect ‘:controller/:action/:id’
    map.connect ‘:controller/:action/:id.:format’

    and one more thing, in the albums controller, you need to change the redirect_to to:
    format.html { redirect_to(:controller => “albums”, :action => “index”) }

  6. Godegberg, could you please provide your routes.rb file?
    You do not need this:
    map.connect ‘:controller/:action/:id’
    map.connect ‘:controller/:action/:id.:format’

    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.

    Thanks!

  7. 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 ‘.

    Again, Thanks! and great Job!

  8. lawl … part of code that i wrote it’s lost because of the special characters … but it’s ok … use the html code for specials characters.

  9. jpemberthy, I am now convinced that this post is haunted! There is something in this post wich gives wordpress bad indigestion…

    I am glad I could help you, and thanks for your advice…

  10. 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.

    Regards, jp.

  11. 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.

    Regards,
    Bill

  12. One thing I noticed on the error page is this line:

    RAILS_ROOT: C:/INSTAN~1.0-W/rails_apps/music_store

    but it should be C:\InstantRails-2.0-win\rails_apps\music_store.

    I know this has nothing to do with the problem I’m having because the tutorial has worked up until this point. Just thought it is strange.

    BTW, I even copied your code from the index.html.erb file above and still get the same error except that now it is referring to line 16.

    Extracted source (around line #16):

    13: �
    14: � “albums”, :action => “show”, :id => album.id %>
    15: � “albums”, :action => “edit”, :id => album.id %>
    16: � ‘Are you sure?’, :method => :delete %>
    17: �
    18:
    19:
    RAILS_ROOT: C:/INSTAN~1.0-W/rails_apps/music_store

  13. Have only started on tut 1 and need time to go over t2.

    As a starter and have been able to use at least two good tuts for Rails2 and the next step along the curve was with routing => link_to.

    So your posting (first one) was good in show the difference in new way (restful naming) and another way to do it (could that be called old way?).

    At this stage along the curve I will grab any hand to get ahead. Many thanks

    Off to read your tut2 .

  14. 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

    Again many thanks for what you have done so far…

    Tony

  15. Great stuff AU_2650!

    I have started working on the part 3, I hope to have it out soon. Although I am a bit over committed at the moment. I will try to finish it…

    I am glad you are making some Rails 2.0 progress! Rails is meant to be fun, isn’t it…

  16. 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.

    Best regards, Daryn

  17. Hi Daryn,

    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.

    Cheers.

  18. 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!

  19. Jim, I think you have a problem with your routing rules. It seems like Rails is interpreting ’2′ as the action. Make sure you are specifying an action. Good luck…

  20. Pingback: Ruby on Rails Tutorials (version 2.0+ compatible)

  21. Hi all,

    I will be posting part 3 fairly soon.

    Sorry for the long wait, I have been a bit busy.

    - Daryn

  22. Pingback: Beginners Tutorial: Routing in Rails 2.0 (with REST) - Part 3 of n « YAB

  23. There seems to be typo under Experiment 2.3/show

    Instead of

    ActionController::Routing::Routes.draw do |map|

    map.connect ‘music’, :controller => “albums”, :action => “index”
    map.connect ”, :controller => “albums”, :action => “show”

    map.connect ‘music/show/:id’, :controller => “albums”, :action => “index”

    end

    it should be

    ActionController::Routing::Routes.draw do |map|

    map.connect ‘music’, :controller => “albums”, :action => “index”
    map.connect ”, :controller => “albums”, :action => “index”

    map.connect ‘music/show/:id’, :controller => “albums”, :action => “show”

    end

  24. Naveet you are 100% correct. Thank you for pointing that out, it is now fixed.

  25. Godegberg, I have just figured out your problem!

    I just happened to read over your problem again and now I get it.
    You are using a URL with albums in it. You should be using a URL with Music in it…

    E.g. /music and not /albums

    Later on we will move back to the more conventional /albums

  26. Pingback: This Week in Ruby (May 12, 2008) | Zen and the Art of Programming

  27. Hello,

    Thank you for your tutorial. God bless you for it.

    I’m running into a small error in the Mongrel output for show.html.erb:

    I get this warning. Anyone know how to fix it?

    music_store/app/views/albums/show.html.erb:12: warning: Object#id will be deprecated; use Object#object_id

    This is the line:

    “albums”, :action => “edit”, id => @album.id %> |

    THANKS in advance,
    –Matt

  28. in Rails 2.0.2
    the root path should be like this:

    map.root :controller => “albums”, :action => “index”

    instead of

    map.connect “”, :controller => “albums”, :action => “index”

  29. Hi,

    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

  30. Hi Mark,

    Have you managed to fix your problem? If not, leave a comment and fill out your full email address in the form and I will email you so that we can sort it out.

    Regards, Daryn

  31. Thanks Jesus, I hope you find the rest of it as helpful.

    Mark, I have emailed you, I did not get a response though. Did you receive my email?
    Let me know if I can help…

  32. I have some problems with final controller. plz help me
    music_store/app/controllers/albums_controller.rb:81: syntax error, unexpected tIDENTIFIER, expecting ‘)’
    format.html { redirect_to(:controller => “albums”, :action => “index&quot }

    whole errors in this line
    anyway i got some idea for routing in this article.
    thank you.

  33. Asanga, I see WordPress has messed up my code….again!

    I think you are missing a ‘)’

    Change your code to:
    format.html { redirect_to(:controller => “albums”, :action => “index”) }

    I will fix the faulty line in my post as soon as possible.
    Probably, later tonight.

    - Daryn

  34. Hi Daryn,

    I figured it out myself.
    Thanks again for this enlightening series!
    Onto part 3 now.

    Cheers,
    Mark

  35. thanks lot.
    but still there are some errors
    music_store/app/controllers/albums_controller.rb:81: syntax error, unexpected tIDENTIFIER, expecting kDO or ‘{‘ or ‘(‘
    format.html {redirect_to(:controller => “albums”, :action => “index”)}&quot }

    If u can plz consider this also

    thanks
    asnaga

  36. Hi Asanga, let me ask you to do one more check. Make sure that you have once closing bracket for each opening one – notice that I only have one ‘}’.

    If that does not fix your problem, let me know and we can fix it via email.
    - Daryn

  37. hi Daryn,
    I know there should end the ‘}’. But didn’t find the place for ‘{‘ for the ending the code. Code is
    format.html {redirect_to(:controller => “albums”, :action => “index”)}&quot }

    first error and all the errors for this line and the error is

    music_store/app/controllers/albums_controller.rb:81: syntax error, unexpected tIDENTIFIER, expecting kDO or ‘{’ or ‘(’
    format.html {redirect_to(:controller => “albums”, :action => “index”)}&quot }

    I try to fix this error but fail.

    thanks lot about ur consideration.
    -Asanga

  38. I have fixed line 81. I needed to add some extra spaces into the line to stop WordPress from manipulating it. My apologise for the confusion that arose from that.
    - Daryn

  39. WordPress question for ya… what’s the name of the plugin you use to render Ruby on Rails code so prettily on your site?

    Thanks so much,
    Liana

  40. I believe there is a typo in the second code fragment shown on this page:

    1. :map.connect ”, :controller => “albums”, :action => “index”

    should not have the leading colon. The corrected line would be:

    1. map.connect ”, :controller => “albums”, :action => “index”

    Thanks for posting this tutorial. It has increased my understanding of Rails routing.

  41. Hello,

    Well I am working on an app and wanted to make some changes on the
    URL’s. I have the following:

    #—
    map.resources :groups do |groups|
    groups.resources :events, :member => { :invite => :get }
    end
    #—

    So my events are mapping into:

    #—
    http://www.xxx.com/groups/1/events/2
    #—

    What I want to do now is take out the ‘group’ from there and only
    leave the id. Make it look like this:

    #—
    http://www.xxx.com/1/events/2
    #—

    I tried something like the following and now I have an events_path
    route that works.

    #—
    map.events ‘:group_id/events’, :controller => ‘events’, :action =>
    ‘index’
    #—

    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.

    map.events_new ….
    map.events_create…

    ..

    It’s there any other way to do this?

    Thanks for your attention,

    Elías

  42. Pingback: Ruby on Rails Tutorials (version 2.0+ compatible) | Seeds To Trees

  43. Hi there, I am trying to run this ruby script using selenium, and I am getting a syntax error for the following statement

    @selenium = Selenium::Client::Driver.new \
    :host => “localhost”,

    Error:

    unexpected tidentifier. expecting $end :host => “localhost”

    Please help

  44. Pingback: Huge post on Rails routing | WP Cookbook

  45. Please continue. Its very important for newbies to understand how routing works in ror and your posts have excellent content required for the same.

    Cheers!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s