Basic Rail’s routing and a journey into the controller
Thanks for tuning in! Last time we spoke, we set up a basic Rails application called the bookstore. Using the new 2.0 scaffolding, we were able to quickly, and effortlessly move from a high-level thought process to a living, breathing model. Now that you’ve toyed around with the application source, I’m going to explain our codevious code and I’ll even throw a little wrench into your gears…basic Rail’s routing.
Open up your bookstore application, if you’ve lost it or found this post randomly…be sure to visit the original post “Ruby on Rails Tutorial, now with more 2.0.2!“. Then, fire up your server, and navigate to your application’s root, likely, http:/localhost:3000. If your code is untouched from the last time we met, you should encounter a “routing error” like so:

That’s kind of annoying, and just a little bit ugy; it’s time we fix this! You may remember play with .htaccess and doing a mod_rewrite here and there, when you use the Rails framework you no longer place the burden of URL rewriting on the webserver, but instead, on Rails. Routes can get really complicated, really fast; so I am going to show you the very basics. Even after I show you how to play around with Rails’ routing, I will leave the application’s default routes alone. I will do this because in teaching, it is much easier explaining to you that:
http://localhost:3000/books/1
is calling on the “books” controller, with the “show” method, and an “id” of 1 verues trying to explain to you that,
http://localhost:3000/library/freakonomics
can do the exact same thing! All in time though, all in time. Anyways, open up theconfig/routes.rb file and you should see something like this:

Routes are listed in order of priority, the higher on the list they are, the higher priority they are. You’ll notice Rails’ default routes on the bottom:
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
Briefly, when a visitor types in the URL:
http://localhost:3000/books/1
Rails takes the HTTP request, looks through the routes listing, and systematically tries to find a match. With the URL above, the HTTP request will be matched to the first request and processed as follows:
http://localhost:3000/:controller/:action/:id
Hopefully this makes sense, I’ll touch more on this down the road. If you’re not entirely lost, recall that the reason we’re poking around the routes file is because we are getting a routing error when we attempt to access “http://localhost:3000″. At the end of the routes.rb file, add the following:
map.root :controller => "books", :action => "index"
“map.root” is the shorthand to name the root path “”; now whenever we navigate to the site’s root path we should see a call to the “books” controller and “index” action. Take note, you do not have to specificy the “index” action, as it is called by default, but I included it for sake of illustration. Navigate to your site’s root, and watch the magic.

Pretty neat, huh? Add a few more books, and then take some time to examine the URL structure of the database items you’ve entered. When you’ve done that, open up the “apps/models/book.rb” file. The file you just opened is our “Book model”, it acts as the gateway between any database queries. Right now it is empty, but it is worth pointing out. Now open the, “apps/controllers/books_controller.rb” file, you will see first entry is the index method.
# GET /books
# GET /books.xml
def index
@books = Book.find(:all)
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @books }
end
end
Since this code was generated by Rails, we have a few lines of commenting. What this means is, any GET request to /books will actaully call the “index” method (we’ll talk about the different request types later). When this method is called in, there are two things that happen.
- We are talking to our “Book model” and asking it to find all records, then we are saving those results as a Ruby hash in “@books”
- Next, depending on the requested format, responding with either an HTML template or XML template (more on this later)
For those readers who have some database expereince, check this out, if this doesn’t make sense, don’t worry.
# ask the Book model to find :all records
@books = Book.find(:all)
# the resulting MySQL query
SELECT * FROM books
Now, scroll down to the next method…it should be named “show”.
# GET /books/1
# GET /books/1.xml
def show
@book = Book.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @book }
end
end
This time, instead asking the Book model to find :all records, we’re asking it to find by the “params[:id]“. What does “params[:id]” mean? The “id” parameter from the URL is accessed by “params[:id]” and in this case, the value is “1″. If we were to type the URL, “http://localhost:3000/books/5″, params[:id] would be set to “5″. Let’s look at this line of code:
@book = Book.find(params[:id])
What we’re doing is assigning the results of our database query, in this case, by asking the Book model to find the record with ID matching params[:id]. You’ll notice that all models are titleized and singular: in this case Book, but it could easily be Author or Category.
Now that you’ve seen how we are retrieving our data from the database, let me show you how to format that data for your visitors. Open your “app/views/books/index.html.erb” file. And you should see this:

If you’ve developed websites in the past, the show view should be a little more familar to you. You will notice a few things that look out of place, with PHP we enclosed our code with the <? code ?> tags, with Ruby, anything enclosed between <% code %> , <%= code %>, is called embedded ruby. Here are the differences:
- <% code %> is evaluted, but not printed
- <%= code %> is evaulated, and printed
Check this:
# this will display NOTHING in your HTML
<% "You will not see this" %>
# this will print the string
<%= "But you will see this!" %>
You can test the code by pasting the embedded ruby code, just below the “<h1>Listing Books</h1>” tag, and accessing your site’s root, like so:

See how that works? Now, the final piece of the puzzle!
<% for book in @books %>
<tr>
<td><%=h book.title %></td>
<td><%=h book.description %></td>
<td><%= link_to 'Show', book %></td>
<td><%= link_to 'Edit', edit_book_path(book) %></td>
<td><%= link_to 'Destroy', book, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
What we’re doing here, is looping through each item in the @books hash, and for each item we are printing out the book title, “book.title” and book description, “book.description”. The “h” you see codeceeding the book title and description is the Rails “HTML escape”. If you type <%= book.title %> instead of <%=h book.title %>, the book title will still dispaly, BUT it is good habit to ALWAYS HTML escape database fields with data that may contain something harmful…read: malicious users entering something other than a book description.
Take a look at the code again, if I were to read it out loud to you it would read as follows:
“For each book in the @books variable, do the following: Print the title; description; and the show, edit, and destroy commands”. To expand on the whole “for” block, here’s another example…if you were feeling rather rebelious, you could do this too:
<% for item in @books %>
<tr>
<td><%=h item.title %></td>
<td><%=h item.description %></td>
<td><%= link_to 'Show', item %></td>
<td><%= link_to 'Edit', edit_book_path(item) %></td>
<td><%= link_to 'Destroy', item, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
Hopefully that makes some more sense
As always, if this was this helpful, if you have questions, or if you just want to bullshit…leave me a comment…help me, help you! Feel like donating to my beer fund?
The next part of our journey through Rails covers RESTful design, an integral part of a properly designed and correctly executed Rails web application.