CONTACT US

LIKE

SHARE

FOLLOW

sebastian-varlan-rails-developer

Rails Developer at ASSIST

Ruby on Rails CRUD and API tutorial

We organized this Saturday a Ruby on Rails Workshop, where the main goal was everyone to understand the basic principles of Rails, by developing a simple application with basic features: CRUD using MySQL database and a basic API using Grape gem. We thought it will be useful for our readers if we share this simple application and try to better explain by publishing a step by step tutorial.

Creating CRUD is a very common task in WEB development. CRUD is standard for:

  • Create
  • Read
  • Update
  • Delete

In this tutorial we will create a Rails CRUD grid, a API CRUD and demonstrate how Rails communicate with a MYSQL database.

So let's get started!

Create a new Rails Application through console:

	rails new crud_api

Open the application generated in a IDE, search for Gemfile file and add the following gem:

	gem 'grape'

Open config/application.rb and add:

    config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
    config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]

Run from console:

	bundle install

Open config/database.yml and set your MYSQL settings. Open app/views/layouts/application.html.erb and insert this lines in head:

	<%= stylesheet_link_tag    'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css' %>
 	<%= stylesheet_link_tag    'https://cdn.datatables.net/s/dt/dt-1.10.10,r-2.0.0/datatables.min.css' %>

this lines before </body>

	<%= javascript_include_tag 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js' %>
	<%= javascript_include_tag 'https://cdn.datatables.net/s/dt/dt-1.10.10,r-2.0.0/datatables.min.js' %>

And replace <%= yield %> with this code:

<div class="container">
<div class="row">
<div class="col-md-12"><% if flash[:notice] %>
<div class="alert alert-success"><%= flash[:notice] %></div>
<% end %> <%= yield %></div>
</div>
</div>

Go to app/assets/javascripts/application.js and add the javascript code that load the jQuery DataTable:

var ready = function() {

    $('#products').DataTable({
        "columnDefs": [
            { "width": "19%", className: "dt-body-center", "targets": -1 },
            { "width": "10%", "targets": 0 },
            { "width": "7%", "targets": 1 },
            { "width": "20%", "targets": 2 },
            { "width": "20%", "targets": 3 },
        ]
    });

}

$(document).ready(ready);
$(document).on('page:load', ready);

Create a new controller from command line:

	rails g controller products index show new create edit update destroy

Create a new model from command line:

	rails g model product name:string price:decimal short_description:text full_description:text

Go to app/controllers/products_controller.rb and write this methods:

class ProductsController < ApplicationController

  # GET method to get all products from database
  def index
    @products = Product.all
  end

  # GET method to get a product by id
  def show
    @product = Product.find(params[:id])
  end

  # GET method for the new product form
  def new
    @product = Product.new
  end

  # POST method for processing form data
  def create
    @product = Product.new(product_params)
    if @product.save
      flash[:notice] = 'Product added!'
      redirect_to root_path
    else
      flash[:error] = 'Failed to edit product!'
      render :new
    end
  end

   # GET method for editing a product based on id
  def edit
    @product = Product.find(params[:id])
  end

  # PUT method for updating in database a product based on id
  def update
    @product = Product.find(params[:id])
    if @product.update_attributes(product_params)
      flash[:notice] = 'Product updated!'
      redirect_to root_path
    else
      flash[:error] = 'Failed to edit product!'
      render :edit
    end
  end

  # DELETE method for deleting a product from database based on id
  def destroy
    @product = Product.find(params[:id])
    if @product.delete
      flash[:notice] = 'Product deleted!'
      redirect_to root_path
    else
      flash[:error] = 'Failed to delete this product!'
      render :destroy
    end
  end

  # we used strong parameters for the validation of params
  def product_params
    params.require(:product).permit(:name, :price, :old_price, :short_description, :full_description)
  end

end

Open app/models/product.rb and let's make some validations on the name, price and short description fields:

  validates :name, presence: true
  validates :price, presence: true, numericality: {:greater_than => 0}
  validates :short_description, presence: true

Now we have a controller and a model, in order to access the application in browser let's add the routes, so open config/routes.rb and add:

  resources :products
  root 'products#index'

The views you can find on github at:

Now the API part, create a folder named api in app, and inside api create products folder. So the structure will be app/api/products. Here create products_api.rb file and insert this code:

module Products
  class ProductsAPI < Grape::API

    format :json

    desc "Product List", {
        :notes => <<-NOTE
        Get All Products
         __________________
        NOTE
    }

    get do
      Product.all
    end


    desc "Product By Id", {
        :notes => <<-NOTE
        Get Product By Id
         __________________
        NOTE
    }

    params do
      requires :id, type: Integer, desc: "Product id"
    end

    get ':id' do
      begin
        product = Product.find(params[:id])
      rescue ActiveRecord::RecordNotFound
        error!({ status: :not_found }, 404)
      end
    end

    desc "Delete Product By Id", {
        :notes => <<-NOTE
        Delete Product By Id
         __________________
        NOTE
    }

    params do
      requires :id, type: Integer, desc: "Product id"
    end

    delete ':id' do
      begin
        product = Product.find(params[:id])
        { status: :success } if product.delete
      rescue ActiveRecord::RecordNotFound
        error!({ status: :error, message: :not_found }, 404)
      end
    end

    desc "Update Product By Id", {
        :notes => <<-NOTE
        Update Product By Id
                        __________________
        NOTE
    }

    params do
      requires :id, type: Integer, desc: "Product id"
      requires :name, type: String, desc: "Product name"
      requires :price, type: BigDecimal, desc: "Product price"
      optional :old_price, type: BigDecimal, desc: "Product old price"
      requires :short_description, type: String, desc: "Product old price"
      optional :full_description, type: String, desc: "Product old price"
    end

    put ':id' do
      begin
        product = Product.find(params[:id])
        if product.update({
                              name: params[:name],
                              price: params[:price],
                              old_price: params[:old_price],
                              short_description: params[:short_description],
                              full_description: params[:full_description]
                          })
          { status: :success }
        else
          error!({ status: :error, message: product.errors.full_messages.first }) if product.errors.any?
        end


      rescue ActiveRecord::RecordNotFound
        error!({ status: :error, message: :not_found }, 404)
      end
    end


    desc "Create Product", {
        :notes => <<-NOTE
        Create Product
         __________________
        NOTE
    }

    params do
      requires :name, type: String, desc: "Product name"
      requires :price, type: BigDecimal, desc: "Product price"
      optional :old_price, type: BigDecimal, desc: "Product old price"
      requires :short_description, type: String, desc: "Product old price"
      optional :full_description, type: String, desc: "Product old price"
    end

    post do
      begin
        product =  Product.create({
                                      name: params[:name],
                                      price: params[:price],
                                      old_price: params[:old_price],
                                      short_description: params[:short_description],
                                      full_description: params[:full_description]
                                  })
        if product.save
          { status: :success }
        else
          error!({ status: :error, message: product.errors.full_messages.first }) if product.errors.any?
        end


      rescue ActiveRecord::RecordNotFound
        error!({ status: :error, message: :not_found }, 404)
      end
    end
  end
end

Now go back to config/routes.rb and add:

	mount Products::ProductsAPI => '/api/products'

Run db:migrate from console to run the migrations:

	rake db:migrate

You can check the application on our Github page. If you have any question please ask below.

Ready to make it happen?

Drop us a line. We’d love to hear from you and see how we can help in solving your digital challenges. As one of the best software outsourcing companies in Romania, Eastern Europe, Europe and the world really, we are sure we can ASSIST.

GET IN TOUCH