How to Build a Todo App with Ruby on Rails

In this tutorial you will get a Ruby on Rails Todo App up and running on your local server, and will push your work into github. If you are casually browsing and are maybe interested in doing a Ruby on Rails tutorial, stop what you are doing RIGHT NOW and give this podcast a listen! It will give you the fuel you need to continue down the web developer path; it definitely fueled me.

Reading and executing tutorials is an amazing way to learn, so roll up your sleeves, take a slug of coffee, and let’s dive in!

This tutorial is loosely transposed from Mackenzie Child’s Youtube Tutorial. I’m transposing this tutorial because Mackenzie flies through the content and I wanted to slow it down a bit. I figured I’d add some value to the Ruby on Rails community and learn a little myself by transposing into blog format.

This tutorial assumes you have Ruby on Rails installed and all other pre-requisites, like github and a text editor and such.

I’m going to run through things as I would do them. It’s not necessarily the way to do it, just how I do it, and — loosely — how Mackenzie Child does it in his tutorial. Let’s dive in:

Get into your terminal and type:

ls

This will bring bring up a list of directories — or folders — such as “Desktop” “Documents” “Downloads” “Library” etc.

Change Directory into “Desktop”:

cd Desktop

Type “ls” to show all available directories

ls

and then jump into the directory you want to store your project in

mine’ll be saved in Projects, so I’ll jump into Projects

cd Projects

You could create a similar folder with the command:

mkdir Projects

Then “cd” into your new folder.

cd Projects

Next, I’m going to call into being the skeleton of my rails app. Easy:

rails new todo

A whole bunch of cool stuff happens in the terminal:

Next, I’ll “cd” into the project folder

cd todo

and check out the files within:

ls

Neat. Now I’ll run the rails server:

rails server

And then navigate to localhost/3000 to make sure everything is working:

Yay! You’re on Rails!

Now I’m going to create a new repository on github, and then commit and push my first commit.

First, create a new repository. Looks something like this:

Hit “create repository” and you’ll get something like this:

We’ll come back to this page, but first go back to your command line terminal, and kill the server with a control + c.

Then type:

git init

And then check the git status with:

git status

You’ll see that you have some untracked files in some red text. Let’s stage those for our first commit with:

git add .

And then check the status again with:

git status

Ah, wonderful. Green text. We’re ready to commit:

git commit -m "first commit"

Then you can head back to your github page to find the remaining code you need:

git remote add origin https://github.com/username/todo.git

Yours will be slightly different, with your username instead of mine, of course.

Then let’s push!

git push -u origin master

If you have any errors, welcome to your first programming challenge! Google that sh!t. The more I learn about programming, the more I learn that you must be a self-sufficient problem solver. Ask for help, but ask google first.

Refresh your github page, and your todo app repository should look something like:

Wonderful.

Next we’re going to get back to our command line and do some “scaffolding”.

rails g scaffold todo_list title:string description:text

Scaffolding is like a shortcut. Scaffolding automatically generates the models, views and controllers you need for a table. A quick google search tells us:

Scaffolding in Ruby on Rails refers to the auto generation of a simple set of a model, views and controller usually for a single table. Would create a full CRUD (create, read, update, delete) web interface for the Users table”

If you’re wondering what a model, view or controller is, this image from codeacademy may help. The image demonstrates the interaction of a person with a webpage:

Forgive me for simplifying too much, but this is my loose understanding: a model is a database, a view is your visual aspects: the html + css, etc. and is exactly what you see on a webpage, and a controller helps the model and the view talk to each other.

Ok, back to programming. We did something to the model, the database, so now we’ve got to run a rake command.

rake db:migrate

What does this do? I’m not completely sure but we can always ask Google. In this case, Google provides us with an answer from stackoverflow.

Let’s check out local server again to make sure everything worked out:

rails server

Instead of http://localhost:3000/, you’ll want to navigate to http://localhost:3000/todo_lists/.

This is the todo list view that the scaffold created. The view becomes plural for some reason. Ask google “why?”.

Add a todo list, and hopefully you get something that looks like:

Now let’s open up our text editor (I’m using sublime 2) and look at our code.

Open up the config/routes.rb file and make the root of the application the todo list controller:

root "todo_lists#index"

Your whole routes.rb file will look something like this:

Rails.application.routes.draw do
resources :todo_lists
root "todo_lists#index"
end

Save the file.

Now boot up the local server again…

rails server

… and see what we just did at http://localhost:3000/!

Instead of the “Yay! You are running Rails” page, we have navigated directly to the todo_lists/index.html.erb page.

If you right-click and look at the page source, you’ll find the same code as you would if you looks at app/views/todo_lists/index.html.erb.

With root “todo_lists#index”, we pointed the root of the app to this todo_lists index page. Cool, huh?

Ok, kill the server (ctrl + c) and let’s write some more code:

rails g model todo_item content:string todo_list:references

With this code, we’re building a model (think “database”) that will store the todo items, nested underneath the todo list.

And what do we do after making changes to the model?

rake db:migrate

You can check your db/migrate files and your app/models files to see what we’ve done. We added a database migrate file:

And we added a todo_list model, with an association to the todo_item model, that says the model “belongs_to :todo_list”

Now we need to make an additional association. Update the todo_list.rb file from:

class TodoList < ApplicationRecord
end

to:

class TodoList < ApplicationRecord
has_many :todo_items
end

SAVE THE FILE.

Now we’re going to get into our routes.rb file and create some routes!

Update this:

Rails.application.routes.draw do
resources :todo_lists
root "todo_lists#index"
end

To this:

Rails.application.routes.draw do
resources :todo_lists do
resources :todo_items
end
root "todo_lists#index"
end

Save, and then see the routes that you created in the terminal by typing:

rake routes

Whew! I’m glad we didn’t have to do that ourselves. Ah, the beautiful laziness of Rails. Or am I the lazy one? Let’s not answer that question.

Next!

We are going to generate a controller for our todo_items. In the terminal, type:

rails g controller todo_items

Hurray! Success!

Check your controller file to see what you’ve done:

Update your todo_items_controller.rb file from:

class TodoItemsController < ApplicationController
end

To:

class TodoItemsController < ApplicationController
before_action :set_todo_list
def create
@todo_item = @todo_list.todo_items.create(todo_item_params)
redirect_to @todo_list
end
private
def set_todo_list
@todo_list = TodoList.find(params[:todo_list_id])
end
def todo_item_params
params[:todo_item].permit(:content)
end
end

So we’ve done a lot here, and I won’t pretend to know everything we’ve done— learning all this myself as we go along — but I do know that we’ve created an action for creating new todo’s, so now we need a form that will let us collect this data from the user in the views.

We will create two “partials” in our views/layouts folder:

_todo_item.html.erb and _form.html.erb

What is a partial? Let’s ask Google:

“Partials in Ruby on Rails. … Partials allow you to easily organize and reuse your view code in a Rails application. Partial filenames typically start with an underscore ( _ ) and end in the same .html.erb extension as your views.”

You might use a different partial for a guest vs. a logged-in user of your website.

Back to adding a form:

First, let’s open the _form.html.erb file and add:

<%= form_for([@todo_list, @todo_list.todo_items.build]) do |f| %>
<%= f.text_field :content, placeholder: "New Todo" %>
<%= f.submit %>
<% end %>

Then, open the _todo_item.html.erb file and add:

<p><%= todo_item.content %></p>

Next, we want to show these items under the todo_lists show.html.erb page.

Update this:

<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= @todo_list.title %>
</p>
<p>
<strong>Description:</strong>
<%= @todo_list.description %>
</p>
<%= link_to 'Edit', edit_todo_list_path(@todo_list) %> |
<%= link_to 'Back', todo_lists_path %>

To this:

<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= @todo_list.title %>
</p>
<p>
<strong>Description:</strong>
<%= @todo_list.description %>
</p>
<div id="todo_items_wrapper">
<%= render @todo_list.todo_items %>
<div id="form">
<%= render "todo_items/form" %>
</div>
</div>
<%= link_to 'Edit', edit_todo_list_path(@todo_list) %> |
<%= link_to 'Back', todo_lists_path %>

Then, pull up the server again.

rails server

I get an error message:

This stumped me for several minutes. I tried googling “missing template ruby” and looked around stackexchange but found nothing that helped.

Then I read: “missing partial todo_items/_form”, “searched in: /Users/deallen/Desktop/Projects/todo/app/views” and realized that maybe my partial file was saved in the wrong place.

Bingo.

After a couple of tries, I eventually got the page to work by saving the _form.html.erb file in the views/todo_items folder rather than the /views/layouts folder:

rails server

Click on “show”, and you are directed to http://localhost:3000/todo_lists/1

Hurray! Successful bug hunt.

Let’s test the form.

Oops. We needed to put both partials under the todo_items folder. Like this:

Fix your code, and then refresh your page. You should be able to add some Todo’s now. I added 2:

Now we’re going to add the ability to DELETE a todo item.

Update your _todo_item.html.erb file from this:

<p><%= todo_item.content %></p>

to this:

<p><%= todo_item.content %></p>
<%= link_to todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>

Refresh to make sure it’s working:

It works, but it doesn’t look too hot, does it? Let’s amend the code to say “Delete” :

<p><%= todo_item.content %></p>
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>

If you tried out your delete button, you would be disappointed.

We need to add a destroy method to our todo_items_controller.rb.

To create the destroy method, add this code into the todo_items_controller.rb:

def destroy
@todo_item = @todo_list.todo_items.find(params[:id])
if @todo_item.destroy
flash[:success] = "Todo List item was deleted."
else
flash[:error] = "Todo List item could not be deleted."
end
redirect_to @todo_list
end

So the whole file will look like:

Try it out!

We’ve done quite a bit, and probably should have made a few github commits by now. I’m going to go ahead and do one now:

git status

Wow. Lot’s of red. Lot’s of changes.

git add .

Let’s see some green.

git status

Ok, let’s commit,

git commit -m "added ability to add todo list, add todo items to lists, and delete todo items"

and then push:

git push

Next we’re going to add the ability to mark an item as “complete”.

Before we can mark an item as “complete” we will need to add a new column to our database:

rails g migration add_completed_at_to_todo_items completed_at:datetime

Which will show you this in the terminal:

And you can go find your new db file that looks like:

We’ve made a change to our database so we need to run the rake db:migrate command:

rake db:migrate

Great. Next we are going to add a route:

Before:

Rails.application.routes.draw do
resources :todo_lists do
resources :todo_items
end
root "todo_lists#index"
end

After:

Rails.application.routes.draw do
resources :todo_lists do
resources :todo_items do
member do
patch :complete
end
end
end
root "todo_lists#index"
end

We also need to add a link to our _todo_item.html.erb view:

Before:

<p><%= todo_item.content %></p>
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>

After:

<p><%= todo_item.content %></p>
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>
<%= link_to "Mark as Complete", complete_todo_list_todo_item_path(@todo_list, todo_item.id), method: :patch %>

We still aren’t ready to mark as “Complete” yet.

Back in our todo_items_controller.rb, we need to add a private method, a before action and a complete method. Those snippets will look like:

def set_todo_item
@todo_item = @todo_list.todo_items.find(params[:id])
end

And,

before_action :set_todo_item, except: [:create]

And,

def complete
@todo_item.update_attribute(:completed_at, Time.now)
redirect_to @todo_list, notice: "Todo item completed"
end

File will look like:

class TodoItemsController < ApplicationController
before_action :set_todo_list
before_action :set_todo_item, except: [:create]
def create
@todo_item = @todo_list.todo_items.create(todo_item_params)
redirect_to @todo_list
end
def destroy
@todo_item = @todo_list.todo_items.find(params[:id])
if @todo_item.destroy
flash[:success] = "Todo List item was deleted."
else
flash[:error] = "Todo List item could not be deleted."
end
redirect_to @todo_list
end
def complete
@todo_item.update_attribute(:completed_at, Time.now)
redirect_to @todo_list, notice: "Todo item completed"
end
private
def set_todo_list
@todo_list = TodoList.find(params[:todo_list_id])
end
def set_todo_item
@todo_item = @todo_list.todo_items.find(params[:id])
end
def todo_item_params
params[:todo_item].permit(:content)
end
end

Now, give it a whirl:

“Todo item completed”

Nice. The item was marked as complete, but nothing else happened. Let’s do something about that.

First, I’m going to update the _todo_item.html.erb file from:

<p><%= todo_item.content %></p>
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>
<%= link_to "Mark as Complete", complete_todo_list_todo_item_path(@todo_list, todo_item.id), method: :patch %>

to:

<div class="row clearfix">
<% if todo_item.completed? %>
<div class="complete">
<%= link_to "Mark as Complete", complete_todo_list_todo_item_path(@todo_list, todo_item.id), method: :patch %>
</div>
<div class="todo_item">
<p style="opacity: 0.4;"><strike><%= todo_item.content %></strike></p>
</div>
<div class="trash">
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>
</div>
<% else %>
<div class="complete">
<%= link_to "Mark as Complete", complete_todo_list_todo_item_path(@todo_list, todo_item.id), method: :patch %>
</div>
<div class="todo_item">
<p><%= todo_item.content %></p>
</div>
<div class="trash">
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>
</div>
<% end %>
</div>

Then, in the todo_item.rb model, I’m going to define this “.completed? method you may have spotted in the first line of the if statement above.

Before:

class TodoItem < ApplicationRecord
belongs_to :todo_list
end

After:

class TodoItem < ApplicationRecord
belongs_to :todo_list
def completed?
!completed_at.blank?
end
end

Go back to your local server, refresh, and hope for success:

YESSSSSS. The Second Todo is struck out and opacitated.

Opacitated? It’s lighter than it was before. The updates I made to the _todo_item.html.erb file worked.

Let’s celebrate with a git commit.

git status

shows a bunch of changed files, then

git add .

then

git status

shows all your files staged for a commit, then

git commit -m "added ability to mark todo items as complete, and added a bit of styling to show the complete status"

then

git push

Ok, great. Now we’re going to work on styling our Todo app.

Navigate to app/assets/stylesheets/application.css

Rename application.css to application.scss so that we can use sass.

What is sass? Google will tell us!

“Sass is a CSS pre-processor with syntax advancements. Style sheets in the advanced syntax are processed by the program, and turned into regular CSS style sheets.”

At this point, Mackenzie just copy/pastes in his own stylings, so we’re going to navigate over to his github for this project and copy/paste his stylings.

Find it yet? It’s here. Copy and paste directly into your application.scss file.

Save.

Refresh.

Wow! Nice, huh?

The next thing we’re going to do is head to the application.html.erb file under views/layouts and put our <%= yield %> inside a container.

Before:

<!DOCTYPE html>
<html>
<head>
<title>Todo</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
    <%= yield %>

</body>
</html>

After:

<!DOCTYPE html>
<html>
<head>
<title>Todo</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<div class="container">
<%= yield %>
</div>

</body>
</html>

Next we are going to take care of the index:

app/views/layouts/todo_lists/index.html.erb

And add the following to the top of the page:

<% @todo_lists.each do |todo_list| %>
<div class="index_row clearfix">
<h2 class="todo_list_title"><%= link_to todo_list.title, todo_list %></h2>
<p class="todo_list_sub_title"><%= todo_list.description %></p>
</div>
<% end %>
<div class="links">
<%= link_to "New Todo List", new_todo_list_path %>
</div>

You can delete the rest of the code underneath! We don’t need it any more. Or comment the code out so that you don’t loose it with:

<!--- COMMENTED-OUT CODE -->

Ok, cool. Now refresh and go back to http://localhost:3000/

Ta-Dah!

Looks pretty awful doesn’t it? That scrunched up text is miserable.

I’m going to dig into the application.scss code to fix it up a bit. Here is the culprit (or at least one of them):

.todo_list_title {
text-align: center;
font-weight: 700;
font-size: 2.5rem;
text-transform: uppercase;
color: white;
margin: 0;
a {
text-decoration: none;
color: white;
transition: all .4s ease-in-out;
&:hover {
opacity: 0.4;
}
}
}

The font is way too big for the title I’ve chosen. So I can update my title, or decrease the font. I’m going to decrease the font:

.todo_list_title {
text-align: center;
font-weight: 700;
font-size: 1.0rem;
text-transform: uppercase;
color: white;
margin: 0;
a {
text-decoration: none;
color: white;
transition: all .4s ease-in-out;
&:hover {
opacity: 0.4;
}
}
}

Cool:

Don’t get comfortable yet! We still have some work to do. Check out that first todo list and tell me it’s not hideous:

In our view/layouts/application.html.erb file we need to add some font links so that our app looks like Mackenzie’s app. Let’s go steal the links from his github file and copy/paste them into our application.html.erb file:

Github file is here.

Before:

<!DOCTYPE html>
<html>
<head>
<title>Todo</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<div class="container">
<%= yield %>
</div>

</body>
</html>

After:

<!DOCTYPE html>
<html>
<head>
<title>Todo</title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<link href='http://fonts.googleapis.com/css?family=Lato:300,400,700' rel='stylesheet' type='text/css'>
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<%= yield %>
</div>

</body>
</html>

You can go ahead and refresh your page but you’ll be disappointed. We still have some work to do.

Get into your _todo_item.html.erb file under app/views. We’re going to replace the “Mark as Complete” with an icon from font-awesome:

<div class="row clearfix">
<% if todo_item.completed? %>
<div class="complete">
<%= link_to complete_todo_list_todo_item_path(@todo_list, todo_item.id), method: :patch do %>
<i style="opacity: 0.4;" class="fa fa-check"></i>
<% end %>
</div>
<div class="todo_item">
<p style="opacity: 0.4;"><strike><%= todo_item.content %></strike></p>
</div>
<div class="trash">
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>
</div>
<% else %>
<div class="complete">
<%= link_to "Mark as Complete", complete_todo_list_todo_item_path(@todo_list, todo_item.id), method: :patch %>
</div>
<div class="todo_item">
<p><%= todo_item.content %></p>
</div>
<div class="trash">
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>
</div>
<% end %>
</div>

Save and refresh!

Cool, but we clearly have more work to do.

Dig back into your _todo_item.html.erb file and update the “else” side of the if /else statement. You can just copy/paste from the “if” side of your statement, but you will want to remove the opacity style and maybe even change the icon.

I went over to the font awesome icon section and found one I liked for the “not completed” todo’s. Mine looks like this:

<div class="row clearfix">
<% if todo_item.completed? %>
<div class="complete">
<%= link_to complete_todo_list_todo_item_path(@todo_list, todo_item.id), method: :patch do %>
<i style="opacity: 0.4;" class="fa fa-check"></i>
<% end %>
</div>
<div class="todo_item">
<p style="opacity: 0.4;"><strike><%= todo_item.content %></strike></p>
</div>
<div class="trash">
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>
</div>
<% else %>
<div class="complete">
<%= link_to complete_todo_list_todo_item_path(@todo_list, todo_item.id), method: :patch do %>
<i class="fa fa-circle-thin"></i>
<% end %>
</div>
<div class="todo_item">
<p><%= todo_item.content %></p>
</div>
<div class="trash">
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>
</div>
<% end %>
</div>

Instead of fa fa-check, I used fa fa-circle-thin:

Next, let’s work on the “delete” buttons:

Before:

<div class="trash">
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>
</div>

After:

<%= link_to todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } do %>
<i class="fa fa-trash"></i>
<% end %>

Don’t forget to update both sides of the If/else statement. The whole code block will look like this:

<!--- 
<p><%= todo_item.content %></p>
<%= link_to "Delete", todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } %>
<%= link_to "Mark as Complete", complete_todo_list_todo_item_path(@todo_list, todo_item.id), method: :patch %>
-->
<div class="row clearfix">
<% if todo_item.completed? %>
<div class="complete">
<%= link_to complete_todo_list_todo_item_path(@todo_list, todo_item.id), method: :patch do %>
<i style="opacity: 0.4;" class="fa fa-check"></i>
<% end %>
</div>
<div class="todo_item">
<p style="opacity: 0.4;"><strike><%= todo_item.content %></strike></p>
</div>
<div class="trash">
<%= link_to todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } do %>
<i class="fa fa-trash"></i>
<% end %>
</div>
<% else %>
<div class="complete">
<%= link_to complete_todo_list_todo_item_path(@todo_list, todo_item.id), method: :patch do %>
<i class="fa fa-circle-thin"></i>
<% end %>
</div>
<div class="todo_item">
<p><%= todo_item.content %></p>
</div>
<div class="trash">
<%= link_to todo_list_todo_item_path(@todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } do %>
<i class="fa fa-trash"></i>
<% end %>
</div>
<% end %>
</div>

Next, we are going to clean up the links. Head over to views/todo_lists/show.html.erb.

Before:

<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= @todo_list.title %>
</p>
<p>
<strong>Description:</strong>
<%= @todo_list.description %>
</p>
<div id="todo_items_wrapper">
<%= render @todo_list.todo_items %>
<div id="form">
<%= render "todo_items/form" %>
</div>
</div>
<%= link_to 'Edit', edit_todo_list_path(@todo_list) %> |
<%= link_to 'Back', todo_lists_path %>

After:

<p id="notice"><%= notice %></p>
<h2 class="todo_list_title"><%= @todo_list.title %></h2>
<p class="todo_list_sub_title"><%= @todo_list.description %></p>
<!-- WE DONT NEED ANYMORE!
<p>
<strong>Title:</strong>
<%= @todo_list.title %>
</p>
<p>
<strong>Description:</strong>
<%= @todo_list.description %>
</p>
-->
<div id="todo_items_wrapper">
<%= render @todo_list.todo_items %>
<div id="form">
<%= render "todo_items/form" %>
</div>
</div>
<%= link_to 'Edit', edit_todo_list_path(@todo_list) %> |
<%= link_to 'Back', todo_lists_path %>

Then we’re going to make those edit / back links look a little better, by placing them inside a div with the class “links”. Remember, we’ve already styled some of our app with the stylesheet we “borrowed” from Mackenzie’s github page. Now, we’re just simply tagging our code with the new stylings.

In the same show.html.erb file, at the bottom, Before:

 <%= link_to 'Edit', edit_todo_list_path(@todo_list) %> |
<%= link_to 'Back', todo_lists_path %>

After:

<div class="links">
<%= link_to 'Edit', edit_todo_list_path(@todo_list) %> |
<%= link_to 'Back', todo_lists_path %>
</div>

Ah! And we have completely forgotten a link to delete the list if we like. So we’ll add that inside the links div with:

 <%= link_to 'Delete', todo_list_path(@todo_list), method: :delete, data: { confirm: "Are you sure?" } %> |

The whole page will look like:

<p id="notice"><%= notice %></p>
<h2 class="todo_list_title"><%= @todo_list.title %></h2>
<p class="todo_list_sub_title"><%= @todo_list.description %></p>
<div id="todo_items_wrapper">
<%= render @todo_list.todo_items %>
<div id="form">
<%= render "todo_items/form" %>
</div>
</div>
<div class="links">
<%= link_to 'Edit', edit_todo_list_path(@todo_list) %> |
<%= link_to 'Delete', todo_list_path(@todo_list), method: :delete, data: { confirm: "Are you sure?" } %> |
<%= link_to 'Back', todo_lists_path %>
</div>

Ok, now that we’ve added a ‘Delete’ button, we need to go back into our todo_lists_controller.rb and fix the Destroy method.

Right now it says:

  def destroy
@todo_list.destroy
respond_to do |format|
format.html { redirect_to todo_lists_url, notice: 'Todo list was successfully destroyed.' }
format.json { head :no_content }
end
end

Which will redirect us to the todo_lists_url, which is not where we want to be. We want to be redirected back to the home page, or root url.

def destroy
@todo_list.destroy
respond_to do |format|
format.html { redirect_to root_url, notice: 'Todo list was successfully destroyed.' }
format.json { head :no_content }
end
end

Test your app to make sure it’s working correctly.

Next we need to get into our new.html.erb file under views/todo_lists and style up the remaining schlokeyness of our app.

Before:

<h1>New Todo List</h1>
<%= render 'form', todo_list: @todo_list %>
<%= link_to 'Back', todo_lists_path %>

After:

<h1 class="todo_list_title">New Todo List</h1>
<div class="forms">
<%= render 'form', todo_list: @todo_list %>
</div>
<div class="links">
<%= link_to 'Back', todo_lists_path %>
</div>

Save. And refresh:

Wow! Looking pretty great.

We’ll want to copy/paste the same stylings into the edit.html.erb file next.

Before:

<h1>Editing Todo List</h1>
<%= render 'form', todo_list: @todo_list %>
<%= link_to 'Show', @todo_list %> |
<%= link_to 'Back', todo_lists_path %>

After:

<h1 class="todo_list_title">Editing Todo List</h1>
<div class="forms">
<%= render 'form', todo_list: @todo_list %>
</div>
<div class="links">
<%= link_to 'Cancel', todo_lists_path %>
</div>

We updated ‘Back’ to ‘Cancel’ and removed the ‘Show’ links because we don’t really need it.

Refresh, and let’s see how we did:

Looking good!

Ok, whelp. That’s about it, I think. Take a look around your new todo app and start getting some sh!t done!

And don’t forget to push all your changes

git status
git add .
git commit -m "Updated style"
git push

That’s it! My code is here if you want to check it out. Please let me know if you have any questions!