--- book: - chapter: - title: Installation page: - body: | 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":http://www.debian.org Linux distribution, you can visit the "Rails On Debian":http://www.rubyonrails.org/show/RailsOnDebian page on the official "Ruby on Rails":http://www.rubyonrails.org 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":http://www.rubyonrails.org/show/GemRails to know how to install the needed packages with Ruby's package manager, "RubyGems":http://rubygems.rubyforge.org. If you run into any problems for installation, you can go to the #rubyonrails IRC channel on the FreeNode network to get further help. title: Installing Rails - title: The database page: - body: | 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":http://phpmyadmin.net (OSX users can use the excellent "CocoaMySQL":http://cocoamysql.sourceforge.net/), 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.
title: Creating the table
- title: Starting the project
page:
- body: |
Now that our table is created, let us start our project. Go into a directory of your choice and run the following command:
$ 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":http://www.mysql.com documentation for
instructions on how to do add users to MySQL.
title: Configuration
- title: Coding the application
page:
- body: |
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":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.
!http://mirror.monsson.dk/rails/congrats.png!
You can use the _-h_ flag to see the different options available in
the server.
title: First steps
- body: |
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?
!http://mirror.monsson.dk/rails/unknown_action.png!
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.
!http://mirror.monsson.dk/rails/template_missing.png!
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@":http://api.rubyonrails.org/classes/ActionController/Base.html#M000032,
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.
!http://mirror.monsson.dk/rails/index.png!
title: Controllers and actions
- body: |
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@":http://api.rubyonrails.org/classes/ActionController/Scaffolding/ClassMethods.html#M000011
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?
!http://mirror.monsson.dk/rails/scaffold_index.png!
You can't tell since we don't have any data, but this new page would
display all the entries in our table.
"@scaffold@":http://api.rubyonrails.org/classes/ActionController/Scaffolding/ClassMethods.html#M000011
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.
title: Scaffolding
- body: |
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.
title: generate scaffold
- body: |
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@":http://api.rubyonrails.org/classes/ActionController/Scaffolding/ClassMethods.html#M000011
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":http://localhost:3000/todo/list.
You'll note that we no longer have the page
"@scaffold@":http://api.rubyonrails.org/classes/ActionController/Scaffolding/ClassMethods.html#M000011
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:
My todo list
<% @items.each do |@item| %>
<%= @item.description %>
<% end %>
And change the list method in *app/controllers/todo_controller.rb* to this:
def list
@items = Todo.find_all
end
Now reload your browser.
!http://mirror.monsson.dk/rails/custom_list.png!
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":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:0x404ca038>, which is not terribly
useful. And finally, we close the loop with @end@ in a pair of tags.
title: "Displaying the items: part I"
- body: "Okay, now it would be nice to be able to see whether an item has been\r\n\
done or not. As I was saying earlier, a little checkbox to the left\r\n\
of the description of the item would be quite nice. Now, we need to\r\n\
have a checkbox that is checked when item is done (when the _done_\r\n\
field is set to 1) and unchecked when it's not (_done_ set to 0).\r\n\
Fortunately, Rails provides us with such a method in ActionView that\r\n\
is called\r\n\
\"@check_box@\":http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M000486.\r\n\
Let's open our *app/views/todo/list.rhtml* file again and add this\r\n\
line of code above the one to display the item's description:\r\n\
\r\n\
\r\n\
<%= check_box(\"item\", \"done\") %>\r\n\
\r\n\
\r\n\
What does this line tell us? The first string given to\r\n\
\"@check_box@\":http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M000486\r\n\
is the variable we want to fetch something from (@item in\r\n\
our case) and what method getter for the information we want.\r\n\
\"@check_box@\":http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M000486\r\n\
automatically takes care of putting the field \"checked\" in the HTML\r\n\
code if @item.done returns a value above 0. Let's reload\r\n\
our page and see what it looks like:\r\n\
\r\n\
!http://mirror.monsson.dk/rails/custom_list_checkbox.png!\r\n\
\r\n\
Very cute, however, does it work if @item.done returns 1?\r\n\
Let's find out, we'll start by adding a link which will automatically\r\n\
take us to the editing view that @scaffold@ made for us. After the\r\n\
@item.description line in *app/views/todo/list.rhtml*,\r\n\
add the following line:\r\n\
\r\n\
\r\n\
<%= link_to(\"Edit\", :action => \"edit\", :id => @item.id) %>\r\n\
\r\n\
\r\n\
Okay, let's explain this line.\r\n\
\"@link_to@\":http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#M000480will\r\n\
creates an hypertext link. The first parameter is the label that\r\n\
should appear on the screen (the part between the tags in\r\n\
HTML.) The next parameters are part of a dictionary of options. The\r\n\
@:action => \"edit\"@ part means that this link should point to the\r\n\
_edit_ action of our controller (the URL will be\r\n\
http://localhost:3000/todo/edit) and the @:id => @item.id@ is to tell\r\n\
the _edit_ action which item we want to modify, so we give the _id_\r\n\
parameter of the item (which makes the URL\r\n\
http://localhost:3000/todo/edit/_x_ where _x_ is the id of our item.)\r\n\
Let's see what it gives on screen.\r\n\
\r\n\
!http://mirror.monsson.dk/rails/custom_list_linkto.png!\r\n\
\r\n\
Click on edit to go the edit page, and change the _done_ field from 0\r\n\
to 1. Click the update button and then the _back_ link to go back to\r\n\
the list view.\r\n\
\r\n\
!http://mirror.monsson.dk/rails/custom_list_checkbox_checked.png!\r\n\
\r\n\
Et voil\xEF\xBF\xBD! Our checkbox perfectly adapts to whether an item has been\r\n\
marked as done or not.\r\n"
title: "Displaying the items: part II"
- body: |
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:
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@":http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M000482
is a
"@FormHelper@":http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html
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.
!http://mirror.monsson.dk/rails/params_inspect.png!
This is what @@params@ looks like. Do you see where _new_item_ and
_description_ we specified in our
"@text_field@":http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M000482
are? Now, let's change the @add_item@ method to actually add the
item. Put this code in place of the
"@render_text@":http://api.rubyonrails.org/classes/ActionController/Base.html#M000032
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 :)
!http://mirror.monsson.dk/rails/add_new_item.png!
title: New items
- body: |
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@":http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M000628
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:
!http://mirror.monsson.dk/rails/destroy_javascript.png!
!http://mirror.monsson.dk/rails/destroy.png!
Yay! We never have to pay bills again!
title: Destroying items
- body: |
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):
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.
title: Changing the done flag
- body: |
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:
* Seperate done items from undone items
* Order the items by description (alphabetical order)
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@":http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M000599,
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:
My todo list
Not done:
<% @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}") %>
<% end %>
Done:
<% @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}") %>
<% end %>
And the result:
!http://mirror.monsson.dk/rails/done_not_done.png!
title: "Displaying the items: part III"
- body: |
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 << "
"
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:
My todo list
Not done:
<%= display_items(@not_done) %>
Done:
<%= display_items(@done) %>
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.
title: "Displaying the items: part IV"
- body: "There is another way with which we can display our items, and it's\r\n\
with the help of _partials_. Partials are basically sub-templates\r\n\
which can be included into a view. Partials are easy to distinguish\r\n\
from regular templates, because their name begins with an underscore\r\n\
(_). Let's see how we can use partials to display our items. First,\r\n\
you'll need to create a file called *app/views/todo/_display.rhtml*\r\n\
(the leading underscore is essential):\r\n\
\r\n\
\r\n\
<%= check_box(\"item\", \"done\", \"onclick\" => \"document.location.href='/todo/toggle_check/#{@item.id}'\") %>\r\n\
<%= @item.description %>\r\n\
<%= link_to(\"Edit\", :action => \"edit\", :id => @item.id) %>\r\n\
<%= link_to(\"Destroy\", { :action => \"destroy\", :id => @item.id },\r\n\
:confirm => \"Are you sure you want to delete this entry: #{@item.description}\") %>\r\n\
\r\n\
\r\n\
\r\n\
We'll now modify our *app/views/todo/list.rhtml* file to use our\r\n\
partial. Remove the lines with our helper method call, and put these\r\n\
three lines in their place:\r\n\
\r\n\
\r\n\
# Not done section\r\n\
<% @not_done.each do |@item| %>\r\n\
<%= render_partial \"display\", @item %>\r\n\
<% end %>\r\n\
\r\n\
# Done section\r\n\
<% @done.each do |@item| %>\r\n\
<%= render_partial \"display\", @item %>\r\n\
<% end %>\r\n\
\r\n\
\r\n\
The\r\n\
\"@render_partial@\":http://api.rubyonrails.org/classes/ActionView/Partials.html#M000112\r\n\
method takes a first string argument which is the name of your partial\r\n\
(the name of your file, minus the leading underscore and the\r\n\
extension) and an item to display (if you look into our partial,\r\n\
you'll see that we use a @@item@ variable.) You can now reload your\r\n\
web browser, and your should have the exact same thing as before.\r\n\
\r\n\
This looping over a collection and displaying them in a partial is\r\n\
such a common thing that there's a method to do just that called\r\n\
\"@render_collection_of_partials@\":http://api.rubyonrails.org/classes/ActionView/Partials.html#M000113.\r\n\
In your controller, remove the lines we've just added, and put those\r\n\
instead:\r\n\
\r\n\
\r\n\
# Not done section\r\n\
<%= render_collection_of_partials \"display\", @not_done %>\r\n\
\r\n\
# Done section\r\n\
<%= render_collection_of_partials \"display\", @done %>\r\n\
\r\n\
\r\n\
And you'll need to add a line to *app/views/todo/_display.rhtml*:\r\n\
\r\n\
\r\n\
<% @item = display %> \r\n\
\r\n\
<%= check_box(\"item\", \"done\", \"onclick\" => \"document.location.href='/todo/toggle_check/#{@item.id}'\") %>\r\n\
<%= @item.description %>\r\n\
<%= link_to(\"Edit\", :action => \"edit\", :id => @item.id) %>\r\n\
<%= link_to(\"Destroy\", { :action => \"destroy\", :id => @item.id }, :confirm => \"Are you sure you want to delete this entry: #{@item.description}\") %>\r\n\
\r\n\
\r\n\
\r\n\
The reason why we added this line is two-fold:\r\n\
# The name of an individual element when using @render_collection_of_partials@ is that of the partial, and I think that @display@ is a particularily bad name to represent a todo item;\r\n\
# We use @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.\r\n\
\r\n\
Now, if you reload the page, you should still have the same thing.\r\n\
\r\n\
Which of helpers or partials is better? I guess that depends on each\r\n\
and every person, however partials have been recently added to Rails\r\n\
to make it easy to display stuff without using helpers or clogging\r\n\
your template with such code.\r\n"
title: "Displaying the items: part V"
- title: Conclusion
page:
- body: |-
Here are a few selected links on Ruby and on Ruby on Rails.
*Rails*:
* "Ruby on Rails":http://www.rubyonrails.org
* "Rails documentation":http://api.rubyonrails.org
* "Rails Academy":http://www.rubyonrails.org/show/RailsAcademy
* "Testing with Ruby on Rails":http://rails.hieraki.org/read/book/4
* "Vim syntax for eRuby":http://vim.sourceforge.net/scripts/script.php?script_id=403
* "Loud Thinking":http://www.loudthinking.com
* "#rubyonrails":irc://irc.freenode.net/#rubyonrails
* "The Rails mailing list":http://lists.rubyonrails.org/mailman/listinfo/rails
Ruby:
* "Ruby":http://www.ruby-lang.org/en
* "ruby-talk":http://groups.google.com/groups?hl=en&lr=&group=comp.lang.ruby
* "ruby-doc":http://www.ruby-doc.org
* "Programming Ruby First Edition":http://www.rubycentral.com/book
* "RubyForge":http://www.rubyforge.org
* "RubyGems":http://rubygems.rubyforge.org
* "RubyGarden":http://www.rubygarden.org
title: Links
- body: "I would like to thank some people who helped make this tutorial:\r\n\
* David Hansson-Heinemeier for Rails, duh :)\r\n\
* #rubyonrails: all the guys on the IRC channel are extremely helpful and fun and really helped me get started with Rails\r\n\
* Jamis Buck for the neat Ruby script to generate a much better looking page\r\n\
* Jonathan Paisley for making some nice suggestions such as talking about the _-c_ option of dispatch.servlet\r\n\
* Robert Bousquet for pointing our a bug with @item.destroy@\r\n\
* Christian Metts for suggesting the use of partials\r\n\
* Peter Kj\xE6r Monsson for mirroring this tutorial\r\n\
* Josh Goebel for all the help with the CSS\r\n\
\r\n\
And finally, a big *thank you* to all the people who decided to try a\r\n\
little-known framework to build web applications, found a tutorial\r\n\
written by a weird french Canadian, tried it and wrote about it on\r\n\
their blogs. I found this tutorial linked on english, french, italian\r\n\
and spanish blogs, thank you so much.\r\n\
\r\n"
title: Thank you
- body: |
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!
title: The End
body: |
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":http://api.rubyonrails.org.
title: How to make a todo list program with Rails 0.9 (out of date)