by: Vincent Foley
NOTE: THIS TUTORIAL IS OUT OF DATE AND I DON’T FEEL LIKE MAINTAINING IT. SOME THINGS IN THERE MAY NOT WORK ANYMORE OR MAY BE WRONG. I HIGHLY RECOMMEND USING THE PRAGMATIC PROGRAMMERS BOOK INSTEAD
This tutorial is intended for first-time users of Rails who want to build a small database-driven application. I’ve chosen to show the creation of a rather simple TODO list program, because it’s short, easy and can be useful. I’ll be using Rails version 0.9.1, with ActionPack 1.0.1, ActiveRecord 1.2.0 and ActionMailer 0.5. If you have any problems, email them to me. If you want information on the methods and classes used in this tutorial, you can visit the Rails API documentation.
In this tutorial, I’ll be using WEBrick as the webserver (comes with Rails, so don’t worry if that didn’t ring a bell) and the MySQL database. In order to be able to build the application, you will need a few software packages. If you are using the Debian Linux distribution, you can visit the Rails On Debian page on the official Ruby on Rails website for informations on which packages you need to install to be up and running. If you are using another distribution or another operating system such as Windows or MacOS, you’ll need to download Ruby’s bindings to MySQL. Then, you’ll want to actually install Rails, to do so, you can visit the page Gem Rails to know how to install the needed packages with Ruby’s package manager, RubyGems. If you run into any problems for installation, you can go to the #rubyonrails IRC channel on the FreeNode network to get further help.
Let’s assume that you have successfully installed Rails, we’ll now get into the meat of the subject, how to build your TODO list program.
The first thing we’ll think about is the database model. Since this is an introductory tutorial, we’ll keep the thing really simple, and have a single table with only three (3) columns: id, description, done. Since I’m really lazy and I don’t like creating SQL tables and databases by hand, I use phpMyAdmin (OSX users can use the excellent CocoaMySQL), but I will give here the SQL query to create our database and table:
-- Create the database CREATE DATABASE `todo` ; -- Create the table CREATE TABLE `todos` ( `id` INT NOT NULL AUTO_INCREMENT , `description` VARCHAR( 100 ) NOT NULL , `done` TINYINT DEFAULT '0' NOT NULL , PRIMARY KEY ( `id` ) );
So, every todo item will have a unique id (by the way, with Rails it is strongly suggested that you always use ‘id’ as your primary key in a table, helps a whole lot) a description and a done flag that indicates whether an item has been done or not.
$ rails Todo
This will output a big listing describing the creation of a bunch of directories and files, setting permissions, etc. Once that is done (should take less than a second), go into that newly created directory.
Now, we will start by editing the main configuration file, config/database.yml. This is what it looks like at first:development: adapter: mysql database: rails_development host: localhost username: root password: test: adapter: mysql database: rails_test host: localhost username: root password: production: adapter: mysql database: rails_production host: localhost username: root password:We will modify database.yml to use our database. Modify the development section to this:
development: adapter: mysql database: todo host: localhost username: root password:
Now our Rails application will use the MySQL database todo. Be sure to modify the username and password fields if you have configured new ones. Refer to the MySQL documentation for instructions on how to do add users to MySQL.
The next step is to create a model and a controller for our applications. To do this, there is a script in the script/ directory called generate. Run these commands:
$ ruby script/generate model Todo $ ruby script/generate controller todo
The name of the model must always start with a capital letter, and by convention the name of your model should be the singularization of the name of your table (e.g: the todos table should have a Todo model) so that ActiveRecord knows which controller to associate with which table.
Now, we will “link” our controller to our model, open app/controllers/todo_controller.rb and modify the file so that it’s like this:
class TodoController < ApplicationController model :todo end
This is pretty self explainatory: the model of our TodoController class is :todo. :todo is a Ruby symbol representing our model (the formula is colon plus the lowercase spelling of our model.)
Now, let’s start the WEBrick server and try to see our application. in the /Todo directory, run the following command:$ ruby script/server
This will start the WEBrick server in development mode on port 3000. Point your browser to http://localhost:3000 and you should see the default Rails page which basically congratulates us for a successful configuration. This message is not really destined to us though, because thanks to WEBrick, there is no configuration :) Congratulations to the people who succeeded in configuring Apache correctly though.

You can use the -h flag to see the different options available in the server.
This is cute, but it’s not what we want, we want to see our application! So let’s add todo/ at the end of the URL. Note that the way to access to a controller is just to add its name to the URL. So, what does that give us?

What is this message? Well, it says we don’t have an index action
(index is the default action of a controller). An action is a method
of a controller in Rails by the way. So, how can we fix this problem?
Let’s open up app/controllers/todo_controller.rb and add the
following lines below the model :todo line:
def index end
This is an empty method definition. In Rails, Ruby methods are actions, so now that we have an index action, what will happen? To know the answer, reload your web browser.

Template missing? What is that? It means that our action exists and
that it works, but it doesn’t have anything to show us. Let’s remedy
that and use a method called
render_text,
change the index method to this:
def index
render_text("This is the index")
end
Let’s reload the page again and see what we get now.

Yipee! It works! However, it’s not terribly useful for managing todo items, is it? Let us try something else, delete the index method we’ve just created and put this line in its place:
scaffold :todo
scaffold
is a method to create a simple database interface for us,
automatically. The argument, :todo is a symbol (a symbol in
Ruby starts with a colon) with the name of our model. What happens if
we reload our index page?

You can’t tell since we don’t have any data, but this new page would
display all the entries in our table.
scaffold
creates many actions: new, edit, destroy, list, show and index. index
just redirects to list, list shows every item in the database,
show gives us only one, new creates a new row and edit lets us
update a row. Play with the scaffold pages to understand what’s in
there. You can surely see that this is an extremely easy and fast way
(unless typing scaffold :todo takes 10 hours and 3 programmers) to
set up a basic database access application. Scaffolding is a great
way to enter initial data in your database.
Another way to do scaffolding is to have the actual code in our controller and views. The generate script has a scaffold action that you can use to put the entire code in your controller and views. You would use it with the following command:
$ ruby script/generate scaffold Todo
You can check it out after this tutorial. For now, we’ll just stick
with the scaffold :todo line.
The problem with scaffolding is that it’s very general and does not really work well for managing a todo list. If you added a new item, you probably saw that you had to enter both the description and the done flag. However, a done flag should always be off when adding an item (right?), so there’s no need to ask the user for that information. Whatsmore, asking the user to input a number to mark a flag is kind of awkward, wouldn’t it be much nicer to have a checkbox? So we’ll write our own actions to make our application nicer to use.
We’ll leave the
scaffold
line in our file, so we can modify entries, remove them, etc. easily,
but we will start adding our own methods.
The first action we’ll make is list to view all our items at once.
So in the file app/controllers/todo_controller.rb, add this method
declaration:
def list end
and point your browser to
http://localhost:3000/todo/list.
You’ll note that we no longer have the page
scaffold
made for us, but rather our “template missing” page. What is this
template missing thing again? Well we don’t have a file to display
our action into. Let’s remedy that and create a blank file in app/views/todo/ called list.rhtml (note, this is .rhtml, not .html)
and if you reload your browser, you should have a blank page. The
name of the view must match that of the action you want it to be
associated with.
Now, how do we get our entries into that page? Well, let’s add code to list.rhtml. Copy this code into list.rhtml:
<html>
<head>
<title>My todo list</title>
</head>
<body>
<% @items.each do |@item| %>
<%= @item.description %>
<br />
<% end %>
</body>
</html>
And change the list method in app/controllers/todo_controller.rb to this:
def list @items = Todo.find_all end
Now reload your browser.

If you added any items while you played with scaffolding, you should see them displayed, if you didn’t, go to http://localhost:3000/todo/new and add an item.
Now, let’s explain what exactly we did here. We’ll start with the
action, because there’s only one line to understand. We basically
find all rows in the todo table and put them in an instance variable
(denoted by the prefix @) called @items.
In the view, we have pretty standard HTML code, except in the body where we have three weird lines. The <% %> and <%= %> tags are ERb tags, and the code between them is Ruby code. The difference between the two is that <%= %> puts its result into the HTML document while <% %> doesn’t.
The view has access to the instance variables declared inside the action method, so this is why we can access the@items variable.
We use a Ruby construct called #each to loop over every element of
@items and we put them into @item. The next
line is used to display the description of the item. description is
a method that was dynamically created because we have a description
column in our todo table and item is an instance of the model for that
table. If our table had a column called chunky_bacon, it would be
possible to say @item.chunky_bacon. If we didn’t call
description, the object representation would’ve been displayed, and
that looks like #<Todo:0×404ca038>, which is not terribly
useful. And finally, we close the loop with end in a pair of tags.
Okay, now it would be nice to be able to see whether an item has been
done or not. As I was saying earlier, a little checkbox to the left
of the description of the item would be quite nice. Now, we need to
have a checkbox that is checked when item is done (when the done
field is set to 1) and unchecked when it’s not (done set to 0).
Fortunately, Rails provides us with such a method in ActionView that
is called
check_box.
Let’s open our app/views/todo/list.rhtml file again and add this
line of code above the one to display the item’s description:
<%= check_box("item", "done") %>
What does this line tell us? The first string given to
check_box
is the variable we want to fetch something from (@item in
our case) and what method getter for the information we want.
check_box
automatically takes care of putting the field “checked” in the HTML
code if @item.done returns a value above 0. Let’s reload
our page and see what it looks like:

@item.done returns 1?
Let’s find out, we’ll start by adding a link which will automatically
take us to the editing view that scaffold made for us. After the
@item.description line in app/views/todo/list.rhtml,
add the following line:
<%= link_to("Edit", :action => "edit", :id => @item.id) %>
Okay, let’s explain this line.
link_to
creates an hypertext link. The first parameter is the label that
should appear on the screen (the part between the tags in
HTML.) The next parameters are part of a dictionary of options. The
:action => "edit" part means that this link should point to the
edit action of our controller (the URL will be
http://localhost:3000/todo/edit) and the :id => @item.id is to tell
the edit action which item we want to modify, so we give the id
parameter of the item (which makes the URL
http://localhost:3000/todo/edit/x where x is the id of our item.)
Let’s see what it gives on screen.

Click on edit to go the edit page, and change the done field from 0 to 1. Click the update button and then the back link to go back to the list view.

Et voil�! Our checkbox perfectly adapts to whether an item has been marked as done or not.
We’ll worry later about making our checkbox change the done flag value. Now, let’s see how to add a new item. Since an item is basically just a short line, we don’t need to make a whole page for new entries, so we’ll just put it in the list view (file list.rhtml.)
We’ll start by adding the following code to our view. Add this after
the <% end %> line:
<hr size=3>
<form method="post" action="add_item">
New item:
<%= text_field("new_item", "description") %>
<input type="submit" value="Add item">
</form>
This adds a simple form at the bottom of the page to input new items.
Note how you can perfectly mix and match ERb code and HTML code.
text_field
is a
FormHelper
method to make text input fields easier. They can load data from the
table, and they make it easy to add new data, which we’ll see in just
a moment. The first argument is an instance variable, the second is a field.
If such a variable has been created in the controller, and it has a
field matching the second argument, the value of that field will be
transferred to the text field. Since we
did not create such a variable, ours will be empty (and that’s what we
want.) However, when we’ll click our Add item button, a
sub-hashtable will be created in @params with new_item as the
key. @params is a variable that is sent in a form action. We’ll
add an action to see what @params looks like. Add this method to
your controller:
def add_item render_text @params.inspect end
Reload your list page, input something in the text zone and press the Add item button.

This is what @params looks like. Do you see where new_item and
description we specified in our
text_field
are? Now, let’s change the add_item method to actually add the
item. Put this code in place of the
render_text
line:
def add_item
item = Todo.new # Create a new instance of Todo, so create a new item
item.attributes = @params["new_item"] # The fields of item should be set to what's in the "new_item" hash
if item.save # Try to save our item into the database
redirect_to(:action => "list") # Return to the list page if it suceeds
else
render_text "Couldn't add new item" # Print an error message otherwise
end
end
Wow, our biggest method to date! Okay, what does this do now? Well, read the comments :)

Okay, now that we can add items, we might want to remove them (maybe they’re quite old, maybe, we don’t have to do a certain task anymore, etc.) Destroying an item is not terribly hard. Open your view app/views/todo/list.rhtml and add the following line below the Edit line:
<%= link_to("Destroy", :action => "destroy", :id => @item.id) %>
I don’t believe I need to explain this line, since it’s almost identical to the Edit line just above it. If you don’t remember what this does, go see how Edit worked.
And also add this to your controller (app/controllers/todo_controller.rb):
def destroy
item = Todo.find(@params["id"])
begin
item.destroy
redirect_to(:action => "list")
rescue ActiveRecord::ActiveRecordError
render_text "Couldn't destroy item"
end
end
This is pretty straight-forward and easy to understand. We select the
item we want to delete (because we got its unique id), and then we try
to
destroy
it. If it works, we return to the list, otherwise, we inform the
user.
This destroy method has one flaw though: it doesn’t ask the user if he/she really meant to delete the item. Let’s remedy that by changing the destroy line in app/views/todo/list.rhtml:
<%= link_to("Destroy",
{ :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: #{@item.description}") %>
Okay, what have we changed? Well, we put braces around the arguments
we already had, those are the options. And then, we have the
html_options, and one of those is :confirm which prompts a small
JavaScript box with a “Yes/No” button pair. If the user presses
“Yes”, Rails takes us to the link, if the user presses “No”, Rails
doesn’t do anything. Let’s take a look:


Yay! We never have to pay bills again!
Okay, the next task for us will be to make that done checkbox work.
We will need to use a bit of JavaScript for this to work. Let’s start
by modifying the check_box call in app/views/todo/list.rhtml:
<%= check_box("item", "done", "onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") %>
The JavaScript part is the "onclick" part. This tells the browser
to go to a URL of our choice; the URL of our choice is /todo/toggle_check/#{@item.id} where, if you remember from earlier,
todo is the controller, toggle_check is the action (this means
we’ll need a toggle_check method) and #{@item.id} is a variable
which holds the unique id of our item. In HTML source, this gives the
following result (for an item of id 2):
<input checked="checked" id="item_done" name="item[done]" onclick="document.location.href='/todo/toggle_check/2'" type="checkbox" value="1" />
Now, we need to write the method toggle_check to make the change in
the database. It’s rather simple really, if our item has a done flag
set at 1, we change it to 0, otherwise we change it to 1.
def toggle_check
item = Todo.find(@params["id"])
# change the done flag. ActiveRecord
# will automatically do the boolean/int
# conversion.
item.done = !item.done?
if item.save
redirect_to(:action => "list")
else
render_text "Couldn't update item"
end
end
Easy, isn’t it? I don’t think there is much to explain in here; it’s very similar to other methods we’ve already written. You can now reload your browser and try that little checkbox and see if it works. No screenshots here though; it’s kind of hard to see me clicking on a checkbox in a screenshot.
Okay, now that we can add new items, edit them with the nice scaffolding page, destroy them and check them, let’s rethink display. Right now, the items are all put together, one after the other, ordered by id. On a notebook this is okay, but a computer can sort things easily for us, so we’ll do two things:
Let’s go into our controller (app/controllers/todo_controller.rb) and we’ll modify a few things in the list method. Make the list method look like this:
def list
@not_done = Todo.find_all("done = 0", "description")
@done = Todo.find_all("done = 1", "description")
end
If you give parameters to
find_all,
the first one is a filter. If it’s nil, no filter is assumed. In our
case, we tell that we want only the items with a done value of 0 in
@not_done and only the items with a done value of 1 in @done.
The second parameter is the SORT BY parameter. If nil, id is
assumed.
However, we are dealing here with things that relate more to the model than to the controller, so it would probably be good to put the routines to find done and not_done items in our model file. So open up app/models/todo.rb and add these two methods to the class:
def self.find_not_done
find_all("done = 0", "description")
end
def self.find_done
find_all("done = 1", "description")
end
These are class methods (denoted by the leading self.) that find the
items matching the done flag and order them by description. You can
now use these in your controller and views. Let’s modify our list
method in our controller, so that it now reads this:
def list @not_done = Todo.find_not_done @done = Todo.find_done end
It’ll work the same as above, but we moved our constraints to the model, which is where they really belong.
So, now that we have our two containers with the values we want, let’s display them.
For this part, I will start doing it the obvious, but ugly way. This is the whole new file that you want:
<html>
<head>
<title>My todo list</title>
</head>
<body>
Not done:<br />
<% @not_done.each do |@item| %>
<%= check_box("item", "done", "onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") %>
<%= @item.description %>
<%= link_to("Edit", :action => "edit", :id => @item.id) %>
<%= link_to("Destroy",
{ :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: #{@item.description}") %>
<br />
<% end %>
<p>
<hr size=3>
<p>
Done:<br />
<% @done.each do |@item| %>
<%= check_box("item", "done", "onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") %>
<%= @item.description %>
<%= link_to("Edit", :action => "edit", :id => @item.id) %>
<%= link_to("Destroy",
{ :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: #{@item.description}") %>
<br />
<% end %>
<hr size=3>
<form method="post" action="add_item">
New item:
<%= text_field("new_item", "description") %>
<input type="submit" value="Add item">
</form>
</body>
</html>
And the result:

Well, it works, but some readers must feel terrible about the code in our view, it’s basically the same code, except of the name of the array containing the items. How do you guys feel about a little refactoring? This will make the file much shorter and cleaner. We will use a helper file to write a method that we will call in our view. Open the file app/helpers/todo_helper.rb and add this method:
def display_items(ary)
result_string = ""
ary.each do |@item|
result_string << check_box("item", "done", "onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") + " "
result_string << @item.description + " "
result_string << link_to("Edit", :action => "edit", :id => @item.id) + " "
result_string << link_to("Destroy",
{ :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: #{@item.description}")
result_string << "<BR />"
end
return result_string
end
Since every one of the methods we use in our views returns text, we just add everything inside a string and then we return that string and it’ll be processed and displayed by the Rails dispatcher. The space added at the end of the first three lines are to put a space between the elements, otherwise they’d all be stuck together. And our new app/views/todo/list.rhtml file looks like this now:
<html>
<head>
<title>My todo list</title>
</head>
<body>
Not done:<br />
<%= display_items(@not_done) %>
<p>
<hr size=3>
<p>
Done:<br />
<%= display_items(@done) %>
<hr size=3>
<form method="post" action="add_item">
New item:
<%= text_field("new_item", "description") %>
<input type="submit" value="Add item">
</form>
</body>
</html>
That’s considerably shorter, isn’t it? And it should please the people who felt bad about the code repetition we had earlier. If you have a lot of code in your view, you should strongly consider moving it to a helper method.
There is another way with which we can display our items, and it’s with the help of partials. Partials are basically sub-templates which can be included into a view. Partials are easy to distinguish from regular templates, because their name begins with an underscore (_). Let’s see how we can use partials to display our items. First, you’ll need to create a file called app/views/todo/_display.rhtml (the leading underscore is essential):
<%= check_box("item", "done", "onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") %>
<%= @item.description %>
<%= link_to("Edit", :action => "edit", :id => @item.id) %>
<%= link_to("Destroy", { :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: #{@item.description}") %>
<br>
We’ll now modify our app/views/todo/list.rhtml file to use our partial. Remove the lines with our helper method call, and put these three lines in their place:
# Not done section <% @not_done.each do |@item| %> <%= render_partial "display", @item %> <% end %> # Done section <% @done.each do |@item| %> <%= render_partial "display", @item %> <% end %>
The
render_partial
method takes a first string argument which is the name of your partial
(the name of your file, minus the leading underscore and the
extension) and an item to display (if you look into our partial,
you’ll see that we use a @item variable.) You can now reload your
web browser, and your should have the exact same thing as before.
This looping over a collection and displaying them in a partial is
such a common thing that there’s a method to do just that called
render_collection_of_partials.
In your controller, remove the lines we’ve just added, and put those
instead:
# Not done section <%= render_collection_of_partials "display", @not_done %> # Done section <%= render_collection_of_partials "display", @done %>
And you’ll need to add a line to app/views/todo/_display.rhtml:
<% @item = display %> <!-- Add this line -->
<%= check_box("item", "done", "onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") %>
<%= @item.description %>
<%= link_to("Edit", :action => "edit", :id => @item.id) %>
<%= link_to("Destroy", { :action => "destroy", :id => @item.id }, :confirm => "Are you sure you want to delete this entry: #{@item.description}") %>
<br>
The reason why we added this line is two-fold:
render_collection_of_partials is that of the partial, and I think that display is a particularily bad name to represent a todo item;check_box, and thus we need to use an instance variable (variable that starts with @), because the first parameter is the string representation of an instance variable. If we did not use one, our checkboxes would always be empty.Now, if you reload the page, you should still have the same thing.
Which of helpers or partials is better? I guess that depends on each and every person, however partials have been recently added to Rails to make it easy to display stuff without using helpers or clogging your template with such code.
Here are a few selected links on Ruby and on Ruby on Rails.
Rails:item.destroyAnd finally, a big thank you to all the people who decided to try a little-known framework to build web applications, found a tutorial written by a weird french Canadian, tried it and wrote about it on their blogs. I found this tutorial linked on english, french, italian and spanish blogs, thank you so much.
Well, that’s the end of this tutorial on Rails, I hope it helped you. Be sure to visit us on IRC on the #rubyonrails channel on the Freenode servers, we like to have fun and help people!