Step by step Tutorial on a Rails CRUD web application

In the last two episodes we saw how to create a simple web application using either Symfony or Laravel. Let’s do the same with Ruby on Rails. In this tutorial we’re gonna combine also another competence we developed in this series of tutorials: Docker.

Fist step, install Docker following this quick guide on the official website: https://docs.docker.com/install. It might be useful (if not necessary) a post installation for Docker, follow these instructions and everthing will work out: https://docs.docker.com/install/linux/linux-postinstall.

The next thing, install Docker Compose for the purpose of completing correctly this tutorial, you will find why as you go along with this reading: https://docs.docker.com/compose/install.

The Ruby programming language

Now that you have all up and running, all you have to do is to create a Ruby on Rails stack on your computer. Let’s start by creating a Docker file, so create a directory named rails_tutorial and put the following content on a file called Dockerfile (without any extension):

$ mkdir rails_tutorial
$ cd rails_tutorial
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

Next, create a bootstrap file named Gemfile which will just load Rails:

source 'https://rubygems.org'
gem 'rails', '5.2.1'

Create an empty Gemfile.lock to build our Dockerfile, type the following instruction at your terminal:

$ touch Gemfile.lock

Finally let’s build our stack, you can do this by putting a file named docker-compose.yml on your project’s root directory:

version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db

It’s time to build it, go to your shell and type the following instructions:

$ docker-compose run web rails new . --force --database=postgresql
$ docker stop rails_tutorial_db_1
$ sudo chown -R $USER:$USER .
$ docker-compose build

Again, let’s configure our database connection, put the following code inside config/database.yml, replacing the previous content:

default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password:
  pool: 5

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

Finally, you need to run the stack and create the database:

$ docker-compose up

Open a new terminal and run the following instruction, make sure you’re inside your project’s root folder:

$ docker-compose run web rake db:create

Now go to your browser, point at this location, http://localhost:3000, and you should see the Rails welcome page. Then we can go inside our Rails container a create a controller, along with its actions:

$ docker exec -it rails_tutorial_web_1 /bin/bash
# bin/rails generate controller Article create view show delete update
# bin/rails generate model Article title:string{100} author:string{50} body:string{1000} url:string{200}
# exit

At this point you should have a migration file under db/migrate on your project’s folder, modify it in the following way (use your favourite editor with sudo):

class CreateArticles < ActiveRecord::Migration
  def change
    create_table :articles do |t|
      t.string :title, limit: 100, :null => false
      t.string :author, limit: 50, :null => false
      t.string :body, limit: 1000, :null => false
      t.string :url, limit: 200

      t.timestamps
    end
  end
end

And run the migration:

$ docker exec -it rails_tutorial_web_1 /bin/bash
# rake db:migrate
# exit

All we have to do now is to write our Rails application, let’s begin with our routes, inside config/routes.rb:

Rails.application.routes.draw do
  get 'article/create'
  post 'article/create'
  get 'article/view/:id', to: 'article#view'
  get 'article/show'
  get 'article/delete/:id', to: 'article#delete'
  get 'article/update/:id', to: 'article#update'
  post 'article/update/:id', to: 'article#update'
end

Now is the time for the controller, put the following code inside app/controllers/article_controller.rb:

class ArticleController < ApplicationController
  def create
    if request.post?
      article = Article.create(title: params[:title], author: params[:author], body: params[:body], url: params[:url])
      redirect_to "/article/view/" + article.id.to_s 
    end
  end

  def view
    @article = Article.find_by(id: params[:id])
  end

  def show
    @articles = Article.all
  end

  def delete
    article = Article.find_by(id: params[:id])
    article.destroy
    redirect_to "/article/show/" 
  end

  def update
    if request.post? 
      article = Article.find_by(id: params[:id])
      article.update(title: params[:title], author: params[:author], body: params[:body], url: params[:url])
      redirect_to "/article/view/" + article.id.to_s 
    else
      @article = Article.find_by(id: params[:id])
    end
  end
end

And finally all our views, this is app/views/article/create.html.erb:

<style>
th, td {
  padding: 10px;
}
th {
  text-align: right;
}
</style>

<h1>Create Article:</h1>

<%= form_tag(nil, method: "post") do %>

<table>
  <tbody>
    <tr>
      <th><%= label_tag(:title, "Title:") %></th>
      <td><%= text_field_tag(:title, nil, :required => true) %></td>
    </tr>
    <tr>
      <th><%= label_tag(:author, "Author:") %></th>
      <td><%= text_field_tag(:author, nil, :required => true) %></td>
    </tr>
    <tr>
      <th><%= label_tag(:author, "Article Body:") %></th>
      <td><%= text_field_tag(:body, nil, :required => true) %></td>
    </tr>
    <tr>
      <th><%= label_tag(:author, "Homepage:") %></th>
      <td><%= text_field_tag(:url, nil, placeholder: "www.example.com") %></td>
    </tr>
    <tr>
      <th></th>
      <td><%= submit_tag("Create") %></td>
    </tr>
  </tbody>
</table>

<% end %>

app/views/article/view.html.erb:

<style>
th, td {
  padding: 10px;
}
th {
  text-align: right;
}
</style>

<h1>Article Created or Modified</h1>

<table>
  <tbody>
    <tr>
      <th>Title:</th>
    <td><%= @article.title %></td>
    </tr>
    <tr>
      <th>Author:</th>
      <td><%= @article.author %></td>
    </tr>
    <tr>
      <th>Article Body:</th>
      <td><%= @article.body %></td>
    </tr>
    <tr>
      <th>Homepage:</th>
      <td><%= @article.url %></td>
    </tr>
  </tbody>
</table>

<br/>
<a href="/article/show">View All</a> -
<a href="/article/update/<%= @article.id %>">Modify</a>

app/views/article/show.html.erb:

<style>
th, td {
  padding: 10px;
}
th {
  text-align: left;
}
</style>

<h1>All Articles</h1>

<% if !@articles.empty? %>
<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>Author</th>
      <th>Body</th>
      <th>Url</th>
      <th>Delete</th>
      <th>Update</th>
    </tr>
  </thead>
  <tbody>
  <% @articles.each do |article| %>
  <tr>
    <td><%= article.title %></td>
    <td><%= article.author %></td>
    <td><%= article.body[0..20] %>...</td>
    <td>
    <% if !article.url.empty? %>
      <a href="http://<%= article.url %>">Visit Url</a>
    <% else %>
      Void Field
    <% end %>
    </td>
    <td><a href="/article/delete/<%= article.id %>">Delete</a></td>
    <td><a href="/article/update/<%= article.id %>">Update</a></td>
  </tr>
  <% end %>
  </tbody>
</table>
<% else %>
  <p>No article found.</p>
<% end %>

<br/>
<a href="/article/create">Create New</a>

app/views/article/update.html.erb:

<style>
th, td {
  padding: 10px;
}
th {
  text-align: right;
}
</style>

<h1>Update Article:</h1>

<%= form_tag(nil, method: "post") do %>

<table>
  <tbody>
    <tr>
      <th><%= label_tag(:title, "Title:") %></th>
      <td><%= text_field_tag(:title, @article.title, :required => true) %></td>
    </tr>
    <tr>
      <th><%= label_tag(:author, "Author:") %></th>
      <td><%= text_field_tag(:author, @article.author, :required => true) %></td>
    </tr>
    <tr>
      <th><%= label_tag(:author, "Article Body:") %></th>
      <td><%= text_field_tag(:body, @article.body, :required => true) %></td>
    </tr>
    <tr>
      <th><%= label_tag(:author, "Homepage:") %></th>
      <td><%= text_field_tag(:url, @article.url, placeholder: "www.example.com") %></td>
    </tr>
    <tr>
      <th></th>
      <td><%= submit_tag("Update") %></td>
    </tr>
  </tbody>
</table>

<% end %>

And that’s it, go to http://localhost:3000/article/create and test the application. If you need this application’s code you can go to my GitHubhttps://github.com/mirkobenedetti/rails_tutorial. Should you need more explanations feel free to contact me in person.

This tutorial is based on Ubuntu 17.10, it might work differently or not be working at all, on other platforms.

Did you like this post? Please share it on your preferred social networks or comment here below, thank you!

6 thoughts on “Step by step Tutorial on a Rails CRUD web application

  1. Hello Mirko,
    everyone in the web development is talking about Rails since quite some time. What’s the reason of this great success?

  2. Hi,
    the reason is simple. ROR is based on Ruby: a concise, powerful, expressive programming language.

    On the other hand its paradigm of ‘convention over configuration’ allows a swift design and development of all the common applications, being flexible enough for custom solutions.

  3. My developer is trying to convince me to move to .net from PHP. I have always disliked the idea because of the costs. But he’s trying none the less. I’ve been using WordPress on various websites for about a year and am anxious about switching to another platform. I have heard great things about dotnetblogengine.net. Is there a way I can transfer all my wordpress posts into it? Any kind of help would be really appreciated!

  4. Hi there. I’m new to the blog world but I’m trying to get started and set up my own. Do you need any HTML coding expertise to make your own WordPress blog? Any help would be greatly appreciated!

  5. Hello Julian,
    No need to master HTML, but a slight knowledge of that together with CSS, could help you to better customize your pages.

    As a starting point you could use free as well as multi licensed themes, which are very cheap. You could next make your own templates or buy a single licensed template.

Leave a Reply

Give me your opinion, I will be grateful.