Introduction
In this article series, we will make, step by step, a fully functioning web application to learn Ruby on Rails. I always found it more helpful to make something "real" while learning something new. This series' goal is to do just that: help me (and you, if you end up reading it) learn Rails faster and better. So, now that we know why I'm trying this, here comes the question: what do we create?
I chose to make an online shop. This application will sell sneakers. I've almost created something along those lines in the past, in a different stack, but it ended up as a missed opportunity. This time, it's just for the sake of learning how to use Rails. Let's jump right into it!
Installation
Before we start writing some code, we need to make sure we have all the tools at our disposal. To get started, we will need three things: Ruby ( the language behind the Rails framework ), Rails ( well, obviously...) and git ( to deploy our application and keep track of our changes ).
If you know you already have those tools, you can skip this and go to the Setup section.
Installing Ruby
Windows
For windows users, you can visit the following link. Click the download button and chose the first link under WITH DEVKIT. Download, follow the steps and open a terminal window to check your ruby version:
>ruby -v
ruby 2.5.3p105 (2018-10-18 revision 65156) [x64-mingw32]
MacOS
On MacOS, depending on the one you have, you probably have Ruby installed already. Check in your terminal with ruby -v
. If that's not the case, install Homebrew and run brew install ruby
in your terminal. After that, run ruby -v
and you should see something resembling this:
>ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]
Installing Rails
Now that we have Ruby, we need to get the Rails framework. In Ruby, we call a package a gem. To install a gem, you use the command gem install [packageName]. The gem command is provided by the package manager RubyGems. So, in our case, open a terminal window and run: gem install rails. Just like before with Ruby, you can check if Rails has been installed by checking its version:
rails -v
Rails 5.2.1
Note: For the rest of the series, I will use this Rails version
Installing Git
Finally, we need to install git. Git is a popular version control system (VCS). A VCS makes it easy to collaborate with others, share and backup your code.
On Windows
For Windows users, you can download Git from this page. Install and follow the steps with the defaults and all should be good. After that, run the command git
in your terminal and you should see something like this:
>git
usage: git [--version] [--help] [-C <path>] [-c <name>=<value>]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
<command> [<args>]
These are common Git commands used in various situations:
start a working area (see also: git help tutorial)
clone Clone a repository into a new directory
init Create an empty Git repository or reinitialize an existing one
work on the current change (see also: git help everyday)
add Add file contents to the index
mv Move or rename a file, a directory, or a symlink
reset Reset current HEAD to the specified state
rm Remove files from the working tree and from the index
examine the history and state (see also: git help revisions)
bisect Use binary search to find the commit that introduced a bug
grep Print lines matching a pattern
log Show commit logs
show Show various types of objects
status Show the working tree status
grow, mark and tweak your common history
branch List, create, or delete branches
checkout Switch branches or restore working tree files
commit Record changes to the repository
diff Show changes between commits, commit and working tree, etc
merge Join two or more development histories together
rebase Reapply commits on top of another base tip
tag Create, list, delete or verify a tag object signed with GPG
collaborate (see also: git help workflows)
fetch Download objects and refs from another repository
pull Fetch from and integrate with another repository or a local branch
push Update remote refs along with associated objects
'git help -a' and 'git help -g' list available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.
On MacOS
On MacOS, we can use Homebrew to install Git. We already installed it because we needed it to install Ruby. So, we can run brew install git
to install the VCS. You should see the same text above when you run git
in a terminal command.
Setup
Now that we have all the tools we need, we can start setting up our new application. In this section, we will create a new bare Rails application and quickly explore what we have to work with. To create a new Rails app, we use the rails new myAppName
command. So, move to a directory where you want to create your app and run rails new sneakers_store
. After creating a whole bunch of new files, you should see something like:
Bundle complete! 16 Gemfile dependencies, 77 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
Now, you can move into the Rails application directory with cd sneakers_store
and open it in your favorite editor to take a peak!
Exploring the application
As you can see, there are a LOT of files and folders there. We won't go into the details of each one right now, because it's not necessary. We'll tackle them when we will need them. But you already have a functional application ( that doesn't do much yet ;) ) Let see some of the files and folders we have:
Gemfile
One of the files you will find in this application in called Gemfile. If you come from Javascript, this is like a package.json. It lists the package requirements for this application. As you can see, there are already quite a few gem required for our little application. You'll notice that there is a strange operand in the file ~>. It tells the bundler ( in charge of loading the required gems ) which gem versions he is allowed to load. For instance, I have:
gem 'rails', '~> 5.2.1'
This means that my app is allowed to use a Rails version superior to 5.2.1 but inferior to 5.3.0. Basically, it will only get minor patches for this gem. If you want an exact version, you can remove the ~>.
app/ directory
The app directory contains the core application code: models, views, controllers and helpers. There is a assets/ folder inside of it that contains the application's assets such as CSS, images or Javascript.
config/ directory
The config directory contains the application configuration. This is where you are going to find our router for example.
test/ directory
No surprises here, this is where our application's tests will be written.
Bundler
Bundler is the tool that manages your application's gems. Earlier, I explained that the ~> syntax in your Gemfile is about what gem versions we allow in our app. Well, Bundler handles managing those dependencies to make sure our development environment is stable. Bundler will install the exact gem versions we need to make sure our application runs smoothly.
When you run rails new, the command bundle install
is run automatically. Each time you make changes to your Gemfile ( adding a new gem, changing a gem's version ), make sure to run bundle install
to take the changes into account.
For the sake of argument, let's just say that I want my rails version to be exactly 5.2.1. I don't wan't any minor patches updates. So, I'll replace the following line in my Gemfile:
gem 'rails', '~> 5.2.1'
by:
gem 'rails', '5.2.1'
You remove the ~> and that indicates you wish an exact version for the gem. Another syntax you might encounter is the following: gem 'rails', '>= 5.2.1'
.
>= means: take the latest version of this gem, as long as this version is greater or equal than the version number provided. In our case, we ask bundle to get the latest rails gem version, as long as the gem version is greater or equal to 5.2.1.
Now, run bundle install
. Bundle will install new gems and/or update gems if necessary. It's possible that you are asked to run bundle update
first. If that's the case, run bundle update
then bundle install
.
So, whenever we are making a change to our Gemfile, make sure to run bundle install
.
rails server
Because we ran rails new
, we already have a application we can run. We run a Rails application with rails server
. Something like this should appear in your terminal:
> rails server
=> Booting Puma
=> Rails 5.2.1 application starting in development
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.0 (ruby 2.5.1-p57), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
Great! Your application is running on port 3000 now. If you visit http://localhost:3000 in your browser, you will see:
Awesome, everything is ready for us to start coding. But before that, we'll go though a little more of high level theory to understand Rails better.
An MVC tale
The Rails framework follows the model-view-controller architectural pattern. The model is responsible for the application's data and its logic. The model represents the the universe in which the application lives. It defines what the user informations are for example, or updates the database. The view is what you see on the browser. The view uses the model and display an interface. Finally, the controller acts as an intermediary between the view and the model. It handles the user's actions and changes the model and view's data.
When you load localhost:3000, a request is sent. That request is sent to the controller. Depending on the code written, the controller might immediately render a view, or interact with a model. After interacting with the model, which can fetch data from the database from example, the controller renders a view with the data gathered.
This calls for a very simplistic schematic representation:
As you can see, the controller sits in the middle of everything. If you look inside tour app/ folder, you have the distinctions between the three types of modules ( controllers/, models/, and views/ ). Let's create our first controller.
Our first controller
To follow the ancient traditions of our people, we have to create an application that say "Hello World!" at some point. Let's do just that. In our controllers folder, let's create a new file called firstcontroller_controller.rb. Let's put the following code inside:
class WelcomeController < ApplicationController
protect_from_forgery with: :exception
def greeting
render html: "Hello World!"
end
end
Note: Controllers file names should end with _controllers.rb and classes end with Controller.
Don't worry to much about the syntax right now. We created a class called WelcomeController that inherits from the ApplicationController. Inside a controller, you can define actions. An action is a public method on the controller, and it is automatically accessible to the web server. Here, I just created an action called greeting. Because Ruby reads almost like English, you can guess what this action does: it renders some HTML: "Hello World!". But that is not enough yet to render our HTML string to a view. For that, we need to modify the router.
Modify the router
The router can be found in config/routes.rb. Open that up and replace the file's content with the following:
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
root "welcome#greeting"
end
We want to make sure the root route uses our new controller. If you follow the link above, you can see the documentation to configure the root route. The syntax is the following:
root controller_name#action_name
Our controller name is welcome and our action name is greeting. Save the file and refresh your browser:
Great! This is a good start. Now, let's deploy our application!
Deploy
The first thing we need to do is to create our git repository. Navigate to the root of the sneakers_store directory and run git init
. You should see something like:
➜ sneakers_store git:(master) ✗ git init
Reinitialized existing Git repository in /Users/Damien/Desktop/ruby/sneakers_store/.git/
Now, run git add .
followed by git commit -m 'first commit'
. The first command will add all the current files to your repository and place them in a staging area. This is pretty much pending changes, the second command indicates the we are sure we want to keep the changes, so we commit them, with a message.
We are going to deploy our application with Heroku. This step is optional but I find it easier to deploy early and often.
Heroku setup
Heroku uses the PostgresQL database. So, this means that we can't use the default sqlite3 we have at the moment. This means we need to change our Gemfile. Here is how it should look like:
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '2.5.1'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.2.1'
# Use Puma as the app server
gem 'puma', '~> 3.11'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# See https://github.com/rails/execjs#readme for more supported runtimes
# gem 'mini_racer', platforms: :ruby
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
# Use ActiveStorage variant
# gem 'mini_magick', '~> 4.8'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.1.0', require: false
group :development, :test do
gem 'sqlite3'
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end
group :development do
# Access an interactive console on exception pages or by calling 'console' anywhere in the code.
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
end
group :test do
# Adds support for Capybara system testing and selenium driver
gem 'capybara', '>= 2.15'
gem 'selenium-webdriver'
# Easy installation and use of chromedriver to run system tests with Chrome
gem 'chromedriver-helper'
end
group :production do
gem 'pg'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
Notice that we removed the sqlite3 gem from the first list to include it in the group :development, :test. The gem pg ( for PostgresQL ) is included in the :production group. Rails lets you specify which gems you need for the different environments. The first list being the gems that are always loaded in each environment.
Now, because we changed our Gemfile, we need to run Bundle again. But, this time, we will add a flag to prevent the installation of the production gems in our local environment:
bundle install --without production
This will not install the pg gem.
Lets re-run git add .
. Then run git commit -m 'Updated Gemfile for production'
.
Heroku CLI
Now, you can sign up for Heroku. Next, download the Heroku CLI. When that is done, check that you have Heroku installed by running heroku --version
in a terminal.
➜ sneakers_store git:(master) ✗ heroku --version
heroku/7.0.52 darwin-x64 node-v10.1.0
Next, run heroku login
and enter your credentials. Then, run heroku keys:add
.
Now, we can create a place on Heroku for our application by runningheroku create
.
➜ sneakers_store git:(master) ✗ heroku create
Creating app... done, ⬢ aqueous-peak-82306
https://aqueous-peak-82306.herokuapp.com/ | https://git.heroku.com/aqueous-peak-82306.git
This is the subdomain just for your application. Of course, it will have a different name than mine.
Deployment on Heroku
To deploy on Heroku, run git push heroku master
. You'll see a bunch of stuff appear in your terminal. When it is done, you can go to your Heroku account dashboard and see your application's subdomain name. Click on it, then click Open app on the top right. And this is what you'll see:
Congratulations! You just deployed your first Rails application on Heroku and you learned how to make your first controller!