Ruby on Rails To Do List Tutorial

 

Today we will be making a to do list application in Ruby on Rails. Ruby on Rails is a web application framework written in Ruby. This tutorial will require some basic knowledge using Terminal. Also, if you are new to ruby on rails, I recommend you check out Railscasts and the Lynda Rails tutorials are great as well. I won’t get into installing ruby here, but if you are on a Mac you already have it. Make sure you have rails (or the latest version, I will be using 2.3.2) by opening Terminal and running:

sudo gem install rails

We will also be using the nifty_generators gem, (on github) so run:

sudo gem install nifty-generators

Then, to set up a new rails application, run:

rails todolist -d mysql

The -d flag specifies that we want to use mysql for our database. The first file we will want to edit is config/database.yml, which is the database configuration file. Edit the development part, as that’s all we will be doing in this tutorial. My section looks like this:


# file: config/database.yml
development:

  adapter: mysql
  encoding: utf8
  reconnect: false
  database: todolist_development
  pool: 5
  username: root
  password:
  socket: /tmp/mysql.sock

Make sure you create a database with that name. Following on, we will be working through the terminal, so you won’t need something like PHPMyAdmin anymore. Let’s start up the server and see what we are presented with. To start the server, run script/server in your terminal. Fire up your web browser and go to 127.0.0.1:3000. Make sure you are using the same version of Rails so that we are on the same page :)

Now we are going to get right into developing. Also, there are only two folder you really have to worry about, the app and public folders. All of your application’s logic goes into the app folder, and things like javascript files and style sheets go into the public folder.

So, let’s get started coding the app! First, pull up Terminal again, and change (cd on unix & mac os x) into your directory, so assuming you left off at running the rails command, run:

cd todolist

Then, we need to create a controller. Rails follow the Model-View-Contoller format. To create our controller, which we will name tasks, run:

script/generate controller tasks

Now that we have our controller, and before we proceed to work on the app, I am going to run:

script/generate nifty_layout

This will give us a nice layout that will be automatically used by Rails, as it will create the application.html.erb template in the app/views/layouts directory. We also need to create a model, which represents a table in our database. To create ours, run the following in Terminal:

script/generate model Task name:string finished:boolean
rake db:migrate

The first line create a model name Task, with two fields, one is name which is a string, and finished which is boolean. While it may look like this is all the table has, Rails automatically adds in three columns: an id column which is set as the primary key, as well as created_at and updated_at.

Now, here is the code for the controller, and I will explain every piece after.

# file: app/controllers/tasks_controller.rb
class TasksController < ApplicationController
    def index
      new
      @tasks = Task.all
    end

    def new
      @task = Task.new
    end
    def create
      @task = Task.new(params[:task])
      if @task.save
        flash[:notice] = 'Task was successfully created.'

        redirect_to :action => "index"
      else
        @tasks = Task.all
        render :action => "index"
      end
    end

    def finish
       @task = Task.find(params[:id])
       new = {:finished => true}
       @task.update_attributes(new)
       redirect_to :action => "index"
    end

    def unfinish
       @task = Task.find(params[:id])
       new = {:finished => false}
       @task.update_attributes(new)
       redirect_to :action => "index"
    end

    def destroy
      @task = Task.find(params[:id])
      @task.destroy

      redirect_to(tasks_url)
    end
end

So starting off with,

class TasksController < ApplicationController

class declares a new class in Ruby, and in this case called TasksController, which inherits from ApplicationController

# file: app/controllers/tasks_controller.rb
def index
  new
  @tasks = Task.all
end

The def declares a new method named index. When you create your rails application, the default routing is controller/method/id, so going to tasks or tasks/index will load the index method. The next line only has new, which tells ruby that you want to execute the new method (this doesnt mean show that page). The next line sets a class variable named tasks, and sets it equal to whats is returned by Task.all. Task (with a capital letter) refers to the model we created earlier, and we execute the method all on it so that it queries the Tasks table for all the records, equaling the SQL code “SELECT * FROM `tasks`”

# file: app/controllers/tasks_controller.rb
def new
  @task = Task.new
end

This method named new only sets up a new Task (not created in the database) and passed it to the page (or returned when the method is run)

# file: app/controllers/tasks_controller.rb
def create
  @task = Task.new(params[:task])
  if @task.save
    flash[:notice] = 'Task was successfully created.'

    redirect_to :action => "index"
  else
    @tasks = Task.all
    render :action => "index"
  end
end

This method actually creates the entry in the database. It takes the data passed to it through post and creates a new instance of a Task, and sets it to a class variable. Then, if the task is saved, the notice is returned and the user is redirected to the index. Otherwise, if it does not save, we set up the class variable with all the tasks that the index action requires, and then redirects them there.

# file: app/controllers/tasks_controller.rb
def finish
   @task = Task.find(params[:id])
   new = {:finished => true}
   @task.update_attributes(new)
   redirect_to :action => "index"
end

def unfinish
   @task = Task.find(params[:id])
   new = {:finished => false}
   @task.update_attributes(new)
   redirect_to :action => "index"
end

These two actions are about the same, with one difference, the finish method finds the task passed to it in the url, sets a local variable to the hash where the symbol finished is set to true. Then we update the row and redirect home. The unfinish method does the exact same thing, except it sets the symbol finished to false. If you are wondering why we are using a symbol here, (the colon in front of the name) it is because it refers to the column.

# file: app/controllers/tasks_controller.rb
def destroy
  @task = Task.find(params[:id])
  @task.destroy

  redirect_to(tasks_url)
end

This last method is pretty self-explanatory, but I will still explain it. First we set a class variable to the task passed to it. Next, we destroy it. Then we redirect the user to tasks_url, which refers to the Tasks controller, and thus the index.

Now let’s create our view. Add a new file in app/views/tasks named index.rhtml

# file: app/views/tasks
<h1>Tasks</h1>

<% form_for @task do |f| -%>
	<%= f.error_messages %>

	<p>
		<%= f.text_field :name %>
		<%= f.submit 'Add' %>
	</p>

<% end -%>

<hr />
<table>
  <tr>
	<p><b>Task</b></p>

  </tr>

<% @tasks.each do |task| %>
  <tr>
    <td width="500"><%=h task.name %></td>
	<% if task.finished %>

	<td><%= image_tag("green.png", :size => "20x20")  %></td>
	<% else %>
	<td><%= image_tag("red.png") %></td>

	<% end %>
	<td><%= if task.finished
			link_to 'unmark finished', :controller => "tasks",
                            :action => "unfinish", :id => task.id
		else
			link_to 'mark finished', :controller => "tasks",
                            :action => "finish", :id => task.id
		end %></td>

    <td>| <%= link_to 'delete', task, :confirm => 'Are you sure?',
        :method => :delete %></td>
  </tr>
<% end %>

</table>

Hopefully this will look somewhat familiar, as it is somewhat html code. The part you might not understand is all the code in either the <%= %> and <% %> tags. This is ruby code. The first part where it says form_for, we are just creating a form by which we can add tasks.

@tasks.each do |task|

This part says, take each item in @tasks and repeat a block for each one with tasks the variable passed.

The code following then refer to columns for each row, so task.name would return the name of the task we are currently working with. Since, finished is a boolean value, we can test it to see what it returns and thus display either a greed or a red dot.

The last code you might be interested in would be the delete link, where we add in a confirm option, which automatically creates javascript (plain-old javascript, no library) that makes sure you really want to delete it.

The last file you will want to take a look at is the app/models/task.rb. We are going to add in some quick validation to make sure they entered a task, so the file will look like:

# file app/models/task.rb
class Task < ActiveRecord::Base
  validates_presence_of :name
end

Since name is the name of the column we want to make sure text is entered into, we add in that code.

There is one last thing we want to add is so that when we got to the site, the site automatically loads the tasks controller. There are two things that need to be done to make this happen. First delete index.html in the public folder. Next open up config/routes.rb. You will need to add in two lines to make sure everything works in the app. Do not forget to add the code before the end tag at the end.

# file: config/routes.rb
  map.resources :tasks
  map.root :controller => "tasks"

At the very end, you should have something that looks like this when you start up the local web server by running script/server in your terminal.

the final product

Download Final Application

A quick note on using the final app: Since this is the final app, you may be confused on what to do so that you can run this app yourself. First you will need to open up the config/database.yml file and make sure the mysql settings are correct for your system on all three sections, development, production and test. Now once that is done, if you have not created the database yet, open up terminal and run:

rake db:create rake db:schema:load

This will create the database and create the tables defined in db/ schema.rb. After this, run script/server and welcome!

Be Sociable, Share!

Related posts:

  1. Stay Productive!!!!
  2. Django Tutorial: Blog Basics
  3. A Detailed Django Tutorial: Blog Basics Part III
  4. A Detailed Django Tutorial: Blog Basics Part II
  5. A Detailed Django Tutorial: Blog Basics Part IV


Written by Brenley Dueck

 

13 Responses to “Ruby on Rails To Do List Tutorial”

  1. shane sponagle Says:

    April 13th, 2009 at 10:10 am

    Cool tutorial. I am not really messing around with ROR anymore but will keep this bookmarked for a rainy day :)

  2. Meshach Says:

    April 13th, 2009 at 12:23 pm

    To be quite honest about it, ROR confuses me greatly.

  3. Mike Says:

    April 17th, 2009 at 5:09 am

    I’m totally new to rails, though I a little experience with rails.

    For me, I had to type
    $ rake db:migrate
    as opposed to
    $ rake dbmigrate

    after creating the task model. I don’t know if this is something in my setup or if it’s a typo.

    Thanks for the article!

  4. Alex Coomans Says:

    April 18th, 2009 at 12:54 am

    Mike, thanks! That probably happened when I was replacing all the symbols with html character signs to make it display right.
    And I am glad you enjoyed it!

  5. Arun V Says:

    June 19th, 2009 at 12:47 pm

    I had to fix a couple of things in index.rhtml to get the above code working.

    1. To create tasks, i had to change the form_for as
    {:action => “create”} do |f| -%>

    2.I had to change the code for delete to this
    | “tasks”, :action => “destroy”, :id=> task.id, :confirm => ‘Are you sure?’ %>

  6. Rolando Murillo Says:

    July 3rd, 2009 at 11:06 pm

    Thanks a bunch. I was trying and trying to learn more about rails but never had the opportunity. You gave it to me.

    Thanks again. Are you using .rhtml instead of .html.erb ’cause you want, right?

  7. ingvi Says:

    August 26th, 2009 at 4:45 pm

    great tutorial, thanks mate.

  8. rob Says:

    September 3rd, 2009 at 11:38 am

    hi, I am relatively new to the whole web development thing — I get this error when I attempt to browse to my default page: Mysql::Error: Table ‘todolist_development.tasks’ doesn’t exist: SHOW FIELDS FROM `tasks`

    I believe I have created the database todolist_development, but it appears the table is not there. Did I miss a step?

    Thanks!

  9. rob Says:

    September 3rd, 2009 at 12:49 pm

    Ok, kind of a noob error…not too sure what I did wrong, but I’ll tell how I fixed. When I first downloaded mysql, I created the database using mysqladmin from the shell. When I was at the mysql prompt, the db didn’t exist! I had to add in the db under mysql for my user name, enter the table and columns along with datatypes and the app is now working…joy

  10. douglas Says:

    December 13th, 2009 at 2:05 pm

    Thanks for the tutorial. How do I get .rhtml files to open in Firefox? I’m pretty new at this. Double clicking open gedit. File > open in Firefox asks which app to use.
    Ubuntu Karmic Koala, rails 2.3.5

  11. jehzlau Says:

    March 23rd, 2010 at 10:34 am

    thanks for writing this tutorial, this is really a big help specially to RoR noobs like me. :)

  12. Edwardo Pawlikowski Says:

    April 17th, 2010 at 8:28 am

    Hi, been reading your blog for a long period. I run a related blogging site although I keep receiving a pile of spam responses, how do you keep your blogging site so clean?

  13. Nayana Says:

    October 20th, 2011 at 1:40 am

    Thank you sir!!
    Great tutorial!!!

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 
connect with me!