Let's make our first Rails app
Jun 9, 2015
Welcome! If you’re here, you’d like to learn to make Rails web apps. I’d love to take you through making the quintessential “To-do” list.
Ingredients
- 1 computer
- 1 Terminal or Command Line Prompt
- 1 installation of Ruby and(on) Rails
- 1 text editor
- 1 happy coder
Recipe
Installing Rails
Getting Rails on your computer is nice and simple, but a bit different depending on what Operating System you’re running:
Windows
It used to be fairly difficult to get a Ruby environment, let alone a Rails one running. Fortunately, the Rails Installer project makes it as simple as downloading the installer for your Windows version and running the installation program. If you’re wondering what version to install, I’d go with the one with the latest Ruby version (2.1).
OS X (10.9 Mavericks or newer)
Mac users have the convenience of having Ruby installed into their computers. Having said that, I’d recommend installing Ruby Version Manager, or RVM. What rvm
offers is full control over what version of ruby you’re running on your Mac, as well as a simple way to install gems (more on that later).
To install rvm
, open your Terminal (Applications -> Utilities) and type in the following:
\curl -sSL https://get.rvm.io | bash -s stable --ruby
This will install rvm
on your Mac, along with the latest version of ruby
.
The next step will require you to close your Terminal window, then re-open it. Why? Because this will let rvm
take over the latest version of ruby
. Next, install rails
with the following Terminal command:
gem install rails
Once again, we’ll get into what a gem
is later on.
Linux
Installing rails
on your Linux machine requires a different command depending on your distribution.
Ubuntu
bash < <(curl -sL https://raw.github.com/railsgirls/installation-scripts/master/rails-install-ubuntu.sh)
Fedora
bash < <(curl -sL https://raw.github.com/railsgirls/installation-scripts/master/rails-install-fedora.sh)
Verifying Your Installation
To double check that everything is running smoothly, you can open up your Terminal or command line and type in the following:
rails -v
What this should do is print in the screen what version of rails
you’re running. If this gives you an error, it’d be a good idea to go back to the last step and make sure you’ve installed everything correctly. In my case, it returns the following:
Rails 4.2.0
If all else fails, I’d suggest making a free account on Cloud9. This is an online platform that takes care of setting up rails
, and is like having your own separate computer on the browser (note: Cloud9 provides a nice button for starting up the server as opposed to starting it from the command line.)
A place to write our code
Text editors are utilities for us to write our code and save it for computer to use when running our program or app. For the purposes of this tutorial, unless you already have one that you know and love, I’d suggest using Atom. It’s open source, and made with a lot of love from the folks at GitHub.
Let’s get this party started!
First, we’ll begin by creating a new rails project.
Open up your terminal. It should open to the home folder on your computer. On a Mac or Linux box, you’d see the following:
cosima:~ ramonh$
Let’s go through what we see here:
cosima
is my computer (huge Orphan Black fan here)~
is the name of the folder we’re currently located in within the Terminal. What is~
, you ask? That’s our home folder. This is a common standard across Unix or Linux OS’ramonh
, perhaps self-explanatorily, is the username.$
after this, your command will be entered
Create your rails
project
After the rails
gem was installed, the rails
command line tool became available to us. We can use it to create a new rails
project:
rails new todo-list
What follows next could take a while. Your output should look something like the following:
create
create README.rdoc
create Rakefile
create config.ru
create .gitignore
create Gemfile
create app
create app/assets/javascripts/application.js
create app/assets/stylesheets/application.css
create app/controllers/application_controller.rb
create app/helpers/application_helper.rb
create app/views/layouts/application.html.erb
create app/assets/images/.keep
create app/mailers/.keep
create app/models/.keep
create app/controllers/concerns/.keep
create app/models/concerns/.keep
create bin
create bin/bundle
create bin/rails
create bin/rake
create bin/setup
create config
create config/routes.rb
create config/application.rb
create config/environment.rb
create config/secrets.yml
create config/environments
create config/environments/development.rb
create config/environments/production.rb
create config/environments/test.rb
create config/initializers
create config/initializers/assets.rb
create config/initializers/backtrace_silencers.rb
create config/initializers/cookies_serializer.rb
create config/initializers/filter_parameter_logging.rb
create config/initializers/inflections.rb
create config/initializers/mime_types.rb
create config/initializers/session_store.rb
create config/initializers/wrap_parameters.rb
create config/locales
create config/locales/en.yml
create config/boot.rb
create config/database.yml
create db
create db/seeds.rb
create lib
create lib/tasks
create lib/tasks/.keep
create lib/assets
create lib/assets/.keep
create log
create log/.keep
create public
Fetching gem metadata from https://rubygems.org/............
Fetching version metadata from https://rubygems.org/...
Fetching dependency metadata from https://rubygems.org/..
Resolving dependencies...
Using rake 10.4.2
Using i18n 0.7.0
Using json 1.8.3
Using minitest 5.7.0
Using thread_safe 0.3.5
Using tzinfo 1.2.2
Using activesupport 4.2.1
Using builder 3.2.2
Using erubis 2.7.0
Using mini_portile 0.6.2
Using nokogiri 1.6.6.2
Using rails-deprecated_sanitizer 1.0.3
Using rails-dom-testing 1.0.6
Using loofah 2.0.2
Using rails-html-sanitizer 1.0.2
Using actionview 4.2.1
Using rack 1.6.1
Using rack-test 0.6.3
Using actionpack 4.2.1
Installing globalid 0.3.5
Installing activejob 4.2.1
Installing mime-types 2.6.1
Installing mail 2.6.3
Installing actionmailer 4.2.1
Using activemodel 4.2.1
Using arel 6.0.0
Using activerecord 4.2.1
Installing debug_inspector 0.0.2
Installing binding_of_caller 0.7.2
Using bundler 1.9.2
Using columnize 0.9.0
Using byebug 5.0.0
Installing coffee-script-source 1.9.1.1
Installing execjs 2.5.2
Installing coffee-script 2.4.1
Using thor 0.19.1
Using railties 4.2.1
Installing coffee-rails 4.1.0
Using multi_json 1.11.0
Installing jbuilder 2.2.16
Installing jquery-rails 4.0.3
Installing sprockets 3.2.0
Installing sprockets-rails 2.3.1
Installing rails 4.2.1
Using rdoc 4.2.0
Installing sass 3.4.14
Installing tilt 1.4.1
Installing sass-rails 5.0.3
Installing sdoc 0.4.1
Installing spring 1.3.6
Using sqlite3 1.3.10
Installing turbolinks 2.5.3
Installing uglifier 2.7.1
Installing web-console 2.1.2
Bundle complete! 12 Gemfile dependencies, 54 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.
run bundle exec spring binstub --all
* bin/rake: spring inserted
* bin/rails: spring inserted
What happened here might look like a lot, and believe me, it is! Put simply, rails
generated most of the files we’ll need to run our web app, as well as installed all the gems we’ll need. Which begs the question…
What exactly is a gem?
Excellent question! I like to think of a gem as exactly the same as a framework or library. That is, a collection of pre-written code available for us to use. If we weren’t using rails
, for example, we’d have to directly write every interaction we’d have with the database in SQL, or each HTTP request out fully. The purpose of gems is to save us the effort of doing so. That doesn’t mean, of course, that knowing how these gems work is not important. Au contraire.
It’s alive! IT’S ALIVE!
Let’s move into the folder of our new rails
app in the Terminal:
cd todo-list
You’ll see the folder name todo-list
in our prompt. Great! We can now start up our server:
rails server
What happens next looks a little odd at first. What’s all this output? Why can’t I put in any more commands?
=> Booting WEBrick
=> Rails 4.2.1 application starting in development on https://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2015-06-10 14:44:46] INFO WEBrick 1.3.1
[2015-06-10 14:44:46] INFO ruby 2.2.1 (2015-02-26) [x86_64-darwin14]
[2015-06-10 14:44:46] INFO WEBrick::HTTPServer#start: pid=23528 port=3000
Do not fear! This is a good sign that you now have a healthy server running. The reason you can’t enter any more commands is because the server for your rails
app is running there. You can even see on the second line how to check it out. Let’s open https://localhost:3000
and see what we’ve got!
… wat. What is this?
No worries! This is a friendly pre-generated webpage to let us know that everything is running smoothly and offer tips on where to go next.
If you want to shut down your server, rails
already told you how to do so on the fourth line of our helpful output. Simply hit Ctrl-C (doesn’t need to be capital C).
Generate a scaffold for our todos
… Generate a what, now? We’ll need to take a step back.
Ever heard of Model View Controller, or MVC?
Image courtesy of Wikipedia
Though it looks complicated, the idea behind this structure of software is quite simple:
- A model stores the data needed for the app. It sends this data for the view to display to the user.
- A view is a visual representation of the data shown to the user
- By interacting with the view, the user sends commands to the controller, which in turn manipulates the data stored in the model
Back to scaffolding
Scaffolding is an automated tool provided by rails
that generates the models, the views, and the controllers for a specific thing you want to control with your web app.
For our app, we can use the scaffold to generate our todo
objects (note: it is vital that we stick to the naming of ‘todo’). That is, we will use the scaffold generator to make our model, view, and controller for the todo
s.
What will todo
s consist of?
Let’s think about what we’ll need to manipulate in a todo
item. We’ll need a title
for it, so we can know what it is we want to do. It would also be good to have a description
, so that the user could put in more text that potentially wouldn’t make sense to be in the title
. Finally, and perhaps most obviously, we’d need to know whether the todo
has been completed
or not.
So let’s make that scaffold for it
Hold on there, let’s look at the actual command first. Instead of you copy pasting it, I’ll show you an example:
rails generate scaffold user username:string email:string password:string date_of_birth:date height:float bio:text
Whoa, what is this? It’s quite simple, really. With this command, we’re generating a scaffold for a user
object. rails generate scaffold
tells rails
that what comes next, that is, the user
will be the name of the thing we’ll be working with. After that come the fields. Our user
will have six fields: username
, email
, password
, date_of_birth
, height
and bio
.
You might be wondering what the parts after the :
’s are. Quite simply, the computer would need to know what type of data we’re working with for each field. So let’s see what each of these are:
string
- A sequence, or ‘string’ of characters.date
- Quite simply, a datefloat
- A floating-point number. That is, a number with decimal pointstext
- A body of text
Hold on - text
and string
sound like the exact same thing, don’t they? Well, no. Simply put, string
stores less data. That is, you allocate less space to store your shorter text. Normally, email addresses and usernames are not very long. However, when it comes to things like bio
’s or description
’s (hint), then you might need more than 500 characters.
Other types include:
integer
- A whole numbertime
- A time of day!binary
- This one is a little more complex.binary
is used for storing data that isn’t as simple as text or numbers. This can be things like music data, photo data, and others.boolean
- Ever heard of these before? A boolean is a type that can have two values:true
orfalse
.
I have a challenge for you, dear reader. You must now generate your rails
scaffold for the todo
. Remember, it will have three fields: title
, description
, and completed
. Can you come up with the data types needed for it? One hint: A todo
can either be completed or not. ;)
What’s all this output?!
If you’ve generated your todo
scaffold correctly, you should see something like this:
invoke active_record
create db/migrate/20150611104736_create_todos.rb
create app/models/todo.rb
invoke test_unit
create test/models/todo_test.rb
create test/fixtures/todos.yml
invoke resource_route
route resources :todos
invoke scaffold_controller
create app/controllers/todos_controller.rb
invoke erb
create app/views/todos
create app/views/todos/index.html.erb
create app/views/todos/edit.html.erb
create app/views/todos/show.html.erb
create app/views/todos/new.html.erb
create app/views/todos/_form.html.erb
invoke test_unit
create test/controllers/todos_controller_test.rb
invoke helper
create app/helpers/todos_helper.rb
invoke test_unit
invoke jbuilder
create app/views/todos/index.json.jbuilder
create app/views/todos/show.json.jbuilder
invoke assets
invoke coffee
create app/assets/javascripts/todos.coffee
invoke scss
create app/assets/stylesheets/todos.scss
invoke scss
create app/assets/stylesheets/scaffolds.scss
Do not be alarmed! I wasn’t kidding when I said that rails
would generate a ton of stuff for us. If you look keenly, you’ll see that we’ve had our model, our views, and our controllers generated for us, as well as other things, like css
and helper
files.
The one we want to look at right now, however, is the file on the second line: the migration
file.
In fact, let’s open it! You can find it within your project folder, and in db/migrate
. It should look something like this:
class CreateTodos < ActiveRecord::Migration
def change
create_table :todos do |t|
t.string :title
t.text :description
t.boolean :completed
t.timestamps null: false
end
end
end
This looks weird, but it’s quite simple. This file will be called and run when we want to set up our database. Databases are typically stored in tables of data. What we are doing here is creating a new table called todos
, where each row will have three columns: title
, description
and completed
. That is, each todo
item will have the three fields, just like we specified in our scaffolding. Neat, huh? If you want to know more about migrations, check out the rails documentation section on migrations. It’s quite handy.
To actually set up our database, we need to tell it to be migrated. rails
provides a bunch of pre-written commands in something called a Rakefile
, that we can invoke by typing rake
into our Terminal, followed by the command we want to run. (If you’re curious, run rake -T
to see what commands are available to you in the Rakefile
).
rake db:migrate
You should see the following output:
== 20150611104736 CreateTodos: migrating ======================================
-- create_table(:todos)
-> 0.0009s
== 20150611104736 CreateTodos: migrated (0.0010s) =============================
Looks simple, and that’s cause it is! All this did was run that migration file we check out earlier and add the todos
table to the database.
Guess what? A huge bulk of the work is already done.
Don’t believe me? Start up your rails
server. Remember how to? Then head over to the website. Again, I’m hoping you remember how to do so. :)
Er.
Well, this is awkward.
Hehehe don’t worry, it’s normal.
Even though we generated a scaffold for the todo
’s, the root
page is still the “Welcome aboard” one. We’ll fix this soon enough, but first, let’s check out our list of todo
’s.
For our convenience, amongst other things, when we generated the scaffold, rails
also generated the URL (the address) for our todo
objects. You just need to enter the localhost address like before, but afterwards append /todos
. In my case, as shown below, it’s simply https://localhost:3000
:
As expected, the list seems empty and we can create new todo
’s.
Creating ‘todo’ items is fairly straightforward, and I don’t think requires a screenshot.
Once we’ve entered it and returned to our list page, we can see our lovely new todo
.
Huh. Well, it works, but the true
or false
entry is kind of bland. For this, I think it would be cool to use icons.
Integrating icons
I’d suggest the handy-dandy Font Awesome. But before we do that, it’s important to first understand…
How our web app is displayed
As you might’ve guessed, if we want to look at and/or change how our web app is displayed, you’re gonna need to look in the app/views
directory, files shown below:
All your pages run the application.html.erb
If you’ve worked with html
files before, you might be a little confused. What is this erb
extension?
erb
, you might have guessed (I sure didn’t) stands for Embedded RuBy. This basically allows you to enter ruby
code tags into your html
. No worries, we’ll get into that in a sec.
So open up that application.html.erb
file and take a look at what’s inside:
<!DOCTYPE html>
<html>
<head>
<title>TodoList</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
As you can see, it’s nice and short.
Those of you familiar with html
could be thrown off with the tags that look like <%
. This is where erb
comes in. It allows you to insert ruby
code to be run. The output of that ruby command is converted to html
.
For example, you’ll see that the erb
calls for stylesheets and javascripts are converted to html
tags (if you’ve never seen html
before, it might be a good idea to go through a tutorial. If you have time, I’d recommend the CodeAcademy one.)
But what about that yield
call?
Well that’s where it gets interesting. When you open a page in your web app, it will display everything here, and then yield
the main part to another html.erb
file, which contains the meat of that page. For instance, when opening the todos/index.html.erb
file, the yield
would convert to the following:
<p id="notice"><%= notice %></p>
<h1>Listing Todos</h1>
<table>
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Completed</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @todos.each do |todo| %>
<tr>
<td><%= todo.title %></td>
<td><%= todo.description %></td>
<td><%= todo.completed %></td>
<td><%= link_to 'Show', todo %></td>
<td><%= link_to 'Edit', edit_todo_path(todo) %></td>
<td><%= link_to 'Destroy', todo, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Todo', new_todo_path %>
I hope that makes sense! While we’re here, let’s take a look at how each todo
is displayed.
The first few lines should coincide with what we normally see in a webpage. We have our header, table with headers, and then comes the table body.
…And then comes the ruby. Don’t worry, it’s quite simple, really.
What we’re doing here is grabbing the list of @todos
, and going through .each
of them. It shall be referred to as a single todo
. We then create a table row where we display its title
, description
, whether it was completed
, and a link to show
it individually, edit
it, or to delete, or destroy
the todo
. The code will then be run for each todo, and that’s how we display each row for each todo
. Simple!
Here, we can edit our completed
field to display a nice icon.
To do so, let’s finally integrate that FontAwesome
icon set.
Integrating Font Awesome into our app
Font Awesome’s Get Started page shows that it’s really simple to add the icon set to your webpage. You need to add the stylesheet:
If you’re familiar with html
, you’d know that we need to add the link to our head
tag. In order to make it available to all pages, we need to do so in…… Which html.erb
file again? ;)
Using them icons
So now that we’ve integrated Font Awesome, we can go ahead and use it!
Open up the todos/index.html.erb
and change the the following line:
<td><%= todo.completed %></td>
…to the following:
<% if todo.completed %>
<% else %>
<% end %>
Finished, right?
Wrong. You, dear reader, have been trolled!
The html
tag for creating a checkmark icon, for example, is <span class='fa fa-check></span>
. Can you deduce where to place it? This would be a great icon for showing that a todo
has been completed.
Once you’ve done that, create the html
tag for the incomplete icon. For a list of icons, check out Font Awesome’s list.
Once you’ve made the changes, refresh that page!
Forgive the pun, but I’d say it looks awesome
.
One final tweak
I’ll show you one more tweak for today. I don’t know about you, but I wasn’t happy with the fact that going to the root
of the website takes me to the “Welcome aboard” page. I want my todos
to be there.
Introducing routes
routes
tell rails
which webpage to show you when you enter a certain address or url
. This is set up automatically when you create a rails
app and is tweaked automatically when you generate pages or scaffolds. Let’s take a looksie in config/routes.rb
:
Rails.application.routes.draw do
resources :todos
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
# root 'welcome#index'
# Example of regular route:
# get 'products/:id' => 'catalog#view'
# Example of named route that can be invoked with purchase_url(id: product.id)
# get 'products/:id/purchase' => 'catalog#purchase', as: :purchase
# Example resource route (maps HTTP verbs to controller actions automatically):
# resources :products
# Example resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Example resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Example resource route with more complex sub-resources:
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', on: :collection
# end
# end
# Example resource route with concerns:
# concern :toggleable do
# post 'toggle'
# end
# resources :posts, concerns: :toggleable
# resources :photos, concerns: :toggleable
# Example resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
end
The parts with the #
are comments, and usually ignored. These are notes left for you, the happy coder! In the second line, you’ll notice the resources: todos
line. This basically tells rails
to treat your todo
pages the way it does, with listing, showing, editing, and creating new todos
.
Let’s tell the routes
to change the root
page to be our todos
page. After the first line, add the following as a new line:
root 'todos#index'
A word to the wise: You’ll probably need to stop the rails
server and start it up again.
Load the root
page again. Check it out! Now you’re on your todo
list, as intended.
So what exactly did we add here? Simply put, we’re telling rails
that the root page is mapped to the todo
’s index
action, which you may recognize as the index.html.erb
view file from earlier.
Not bad, huh?
You’ve just made an app in rails
. Take a moment to pat yourself in the back.
This should give you a jumpstart into the world of web app development with rails
. As you can probably tell, we’re barely scratching the surface. If you’re itching to do more practising, try doing things like changing the show
, edit
and destroy
links into icons, or try adding a field to your todo
model.
Ideally, if guides could go on forever, I’d show you how to take the style of the website to the next level using Twitter Bootstrap, but that shall be for another time.
Toodles!
Buy me a coffee @hola_soy_milk