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

02_routing.jpg

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 the app/config/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.

  1. 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”
  2. 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:

1
2
3
4
5
# 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 preceeding 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:

1
2
3
4
5
6
7
8
9
10
<% 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 commen…help me, help you!

The next part of our journey through Rails covers RESTful design, an integral part of a properly designed and correctly executed Rails web application.

27 Responses to “Basic Rail’s routing and a journey into Views, and Controllers”

  1. Ruby on Rails Tutorial, now with more 2.0.2! | jonathan s ng Says:

    [...] out part two, “Basic Rail’s routing and a journey into Views, and Controllers”! in Ruby on Rails and Tutorials. Feed for this Entry Trackback [...]

  2. KS Says:

    Good stuff

  3. e Says:

    This is great, please do post some more, it’s hard to find rails 2.0 tutorials out there!

  4. Howdy Says:

    This was a very good walkthrough of a simple ruby application.
    There is so much “junk” out there that never gives the most important points.

  5. Oscar Says:

    Superb!!!!! Big thanks to you as most of the tutorial on the internet isn’t working anymore.

  6. Barry Says:

    Great timing with this one. Encore!

  7. Marc Says:

    Thank you for the post, enjoyed reading.

    Need some help understanding routes, I am using a webhost and created a subdomain which points to the app/view/”folder of application”
    Navigating to the subdomain, I get a listing of the files in there rather than index.html.erb being used, as index.html would. Also when I have Time.now add as a variable to see the current time on the index page it doesnt get processed. Hope this helps in understanding the problem I am having.

    Thanks in advance

    Marc

  8. depace Says:

    helpful… thanks

  9. Leave a Reply Says:

    Why do the four commands not look standard? Show just has book, Edit has edit_book_path(book), Destroy uses :method => :delete, and New port uses new_post_path. Where do they go and how are they linked to everything else?

  10. Mitch Says:

    Hi, I’ve checke your site meeta.com, great job,
    but, how did you manage to implement authentication? Which option do you feel it’s the best?

    Thx

  11. Qubess Ali Says:

    Hi,

    Thank you so much for this gr8 Tutorial. I rate this 10 out of 10. I have found your tutorial very helpful.

    With Best Regards
    Qubess Ali

  12. Zain AlAbdin Says:

    Loved your tutorials!
    thanks a lot
    more more more more more more please!

  13. Fred Karlsson Says:

    Brilliant! This tutorial got me going with RoR within a few minutes.

    You have a great talent for explaining things in an easy-to-follow manner.

  14. Nik Kantar Says:

    A nice followup to the first part.

    It might be worth mentioning to the reader that he/she needs to delete public/index.html in order for the index route to work.

  15. Jonathan Says:
    The methods (edit_book_path, destroy using :method => :delete, and new_post_path) do not look standard because they use something called resources. This is a little tricky, and I will be devoting a post to it.

    Nik: I overlooked that, thanks.
    Mitch: Authentication, for what? User login?

  16. Tim Says:

    Keep up the fantastic work.. I’m eagerly waiting for the next part.

    Cheers,

    Tim

  17. Mike Says:

    Great Tutorial. A small thing (perhaps) Books is not a Hash, it’s an Array. Edit the controller and add the line “puts @books.class” (without the quotes), then look at the server console!!!
    Likewise @books[0].class is an element of the Array, namely a Book.

  18. Mark Says:

    Third paragraph, there is a repeated word:

    “I will leave leave the application’s”

    Mind you, I only point this out because I find this to be one of the clearest-written, easy-to-understands Rails 2.x guides I’ve seen yet, and I want its popularity to grow ;)

  19. Une Says:

    Great! Many thanks! Can’t wait for the next episode.

  20. hayden Says:

    thank you very much, i’ve looked at many many many tutorials for ruby, and your’s had definately been the most kind to a beginner like myself. and the what i’ve learned thusfar has been invaluble to me. thank you once more, and i will continue your tutorial, and hope to see more amazing work.
    THANKS =D

  21. Al Says:

    Thanks for your contribution here.

  22. Al Says:

    Your effort is appreciated!

  23. Queue Says:

    Just another schmo wanting to say thanks. Thanks!

  24. Jack Says:

    This is a great little introduction. I was able to follow it without knowing anything about ruby or rails. C was the last language I programmed in years ago. I started to learn Javascript this past year but Ruby on Rails seems like the best choice if I’m only planning to learn one. Really, I just want to be a code cobbler, gluing together pieces to make little apps. The RoR community seems enthusiastic so I’m hoping to do as little coding as possible.

    I really appreciate that you took the time to create this tutorial.

    Thanks

  25. MellifluidicPulse Says:

    Awesome stuff (also with the first page)! I know I’m basically echoing those who’ve come before me, but it is great to have stuff out there for 2.0. If I may make a couple suggestions, you might want to remind people on the previous page that they need to actually create their database and set their password in the database.yml file (If they set one other than default). This had me tripped up for a bit. Again though - awesome job!

  26. Dale Says:

    Great job! I have been spending days piecing this all together and this made it all fit together.

  27. Jonathan Says:
    I’ll add in the database configuration, sometimes I forget all my local development stuff is root with no password :)

Leave a Reply