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>

<br />

<%= 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>

<br />

<%= 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>

<br /> 

<%= 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:


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

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

<%= 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| %>
  <p>
    <b>Title</b><br />
    <%= f.text_field :title %>
  </p>

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

  <p>
    <%= f.submit "Update" %>
  </p>
<% 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| %>
  <p>
    <b>Title</b><br />
    <%= f.text_field :title %>
  </p>

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

  <p>
    <%= f.submit "Create" %>
  </p>
<% 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&quot ;) }
      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

31 Responses to “Beginners Tutorial: Routing in Rails 2.0 (with REST) - Part 2 of n”

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

    [...] Part 2 is now available… [...]

  2. darynholmes Says:

    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. NKJ Says:

    Thank you! I have enjoyed this one. Looking forward to the next.

  4. Stefano Diem Benatti Says:

    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!

  5. Godegberg Says:

    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?

  6. Godegberg Says:

    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” ;) }

  7. darynholmes Says:

    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!

  8. jpemberthy Says:

    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!

  9. jpemberthy Says:

    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.

  10. darynholmes Says:

    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…

  11. jpemberthy Says:

    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.

  12. Bill Thayer Says:

    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

  13. Bill Thayer Says:

    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

  14. AU_2650 Says:

    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 .

  15. Zia Says:

    Good stuff man!
    looking forward to the third part of this useful serious!

  16. AU_2650 Says:

    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

  17. darynholmes Says:

    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…

  18. darynholmes Says:

    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

  19. plasante Says:

    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.

  20. jim Says:

    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!

  21. darynholmes Says:

    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…

  22. Ruby on Rails Tutorials (version 2.0+ compatible) Says:

    [...] Beginners guide/Learning Routes part 1 part 2 [...]

  23. darynholmes Says:

    Hi all,

    I will be posting part 3 fairly soon.

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

    - Daryn

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

    [...] the end of part 2, routes.rb looked like [...]

  25. Navjeet Says:

    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

  26. darynholmes Says:

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

  27. darynholmes Says:

    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

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

    [...] in Rails 2 was recently published. If you haven’t done so, follow the links to part 1, 2, 3 and [...]

  29. Matthew J Mucklo Says:

    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

  30. darynholmes Says:

    Hey Matthew, I am glad you are enjoying the tutorial.

    With regards to your problem, I recommend you look at these links for help:
    http://forums.site5.com/showthread.php?t=9101
    http://dev.rubyonrails.org/ticket/6585

    I hope that helps…

  31. leon Says:

    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”

Leave a Reply