Ruby on Rails E-commerce API for Beginners — Part 1

DZone 's Guide to

Ruby on Rails E-commerce API for Beginners — Part 1

For any beginners looking to develop e-commerce applications, check out this multi-part ruby tutorial and learn how.

· Web Dev Zone ·
Free Resource

Have you ever bought anything online? Of course you have! Millions of people do around the globe every day. E-commerce has already become very popular and is still gaining more and more supporters.

It is not only a way to buy things, but a way to sell them as well. One cannot even count how many online-shops there are on the Internet. Some of them are very poorly made, but there are also many eye-catching ones. Guess which of them are more likely to attract a new customer?

E-commerсe sites have no geographical limits, so the number of people who would like to manage an online business is constantly growing. Our company, MLSDev, is fully behind this progress. We create great and successful online-service apps for our clients. You can check a couple of them out here:

GoPuff - http://gopuff.com/

Rive - http://getrive.com/

If you like these examples and are a beginner at developing e-commerce applications then you may find the following information quite useful.

Our developers work with Ruby on Rails to provide back-end solutions for projects. It is not easy “cooking” up code, especially for those who do not stick with it. But don’t worry, we have prepared a detailed “recipe” for beginners on how to create an API for an E-commerce website. Just follow our detailed instructions and you will succeed.

Today we will present the first part of our “E-commerce API recipe” that deals with creating products. It is going to be very informative, so get ready and start the “development cooking”.

1. First of all, you need to install Ruby 2.2.3 and Ruby on Rails 4.2.4. You can read about the installation process here

2. Create a new app and name it “Shop” for example. Write the command in the console to do that: 

    rails new Shop --skip-sprockets --skip-spring --skip-javascript --skip-turbolinks --skip-test-unit --database=postgresql  

To learn more about the keys used in the command:

    rails new --help  

3. Do a preliminary application setup. Set up Ruby on Rails generators first by placing this code into the file config/initializers/generators.rb.

Rails.application.configure do 
  config.generators do |g|
    g.orm :active_record, migration: true
    g.test_framework :rspec, fixtures: false
    g.helper false
    g.decorator false
    g.controller assets: false

The next step is testing the environment setup. We will use RSpec for the app testing. Not a big deal, just add the following to the Gemfile:


group :development, :test do
  gem 'rspec-rails'

group :test do
  gem 'shoulda-matchers'
  gem 'rspec-activemodel-mocks'
  gem 'rspec-its'

 To install new gems write the command in the console:

bundle install # (or just bundle)

 Then set up RSpec for the project by running this command in the terminal:

rails generate rspec:install # (or use a shortcut: rails g rspec:install)

A newly generated spec/ directory will be the result of all previous instructions completed successfully. This is where we are going to write tests.   

4. As we create only API for an e-commerce website we need to write the following code in the file config/routes.rb: 

    namespace :api do

 config/routes.rb is the file where we will set up the routes to the resources.

As the next step let’s plan the API architecture. Since all controllers are inherited from ApplicationController we will arrange such methods as new, create, update, destroy: 

    class ApplicationController < ActionController::Base

     def new

     def create


     def update
       resource.update! resource_params

     def destroy


Thus, when we create controllers for our online-shop API we will be able to redefine private methods initialize_resource, build_resource, resource. This will help us to keep the controllers lightweight.

5. Now it is the right time to add something to our online shop... it is impossible to have a shop without the products. Create the model “Product”, that will contain such fields for example: name, price, description. Let’s type the command in the console:

     rails generate model Product name:string price:integer description:text  

This command will generate the model product.rb in the folder app/models/ with the fields name(type string)price(type integer)description(type text) and the migration to the database db/migrate/(timestamp)_create_products.rb. The file where we will write tests for the model spec/models/product_spec.rb. will be generated too.

Then write the command in the console to create a database: 

    rake db:create 

 After that write the command to conduct the created migration to the database:

    rake db:migrate  

The next step is to create an API controller, ProductsController, where we will process requests to API of the products. Let’s start with writing tests for the controller. Create the file spec/controllers/api/products_controller_spec.rb and add the following code: 

    require 'rails_helper'

   describe Api::ProductsController do


 We will write tests for routes first:

     require 'rails_helper'

   describe Api::ProductsController do
     it { should route(:get, '/api/products').to(action: :index) }

     it { should route(:get, '/api/products/1').to(action: :show, id: 1) }

Go to the console and type the command rake, you will see that tests do not work and there are two errors on the screen.

Screen #1a.jpg

What's next? Has everything been done in vain? Don’t panic, we just need to fix that. Go to config/routes.rb and write:

    namespace :api do
     resources :products, only: [:index, :show]

 Let’s check if the tests run this time. Drumroll… Voila, there are two green dots!

We also need to write tests for actions. Let’s add them to other tests.

    RSpec.describe Api::ProductsController, type: :controller do


  describe '#index.json' do
    before { get :index, format: :json }

    it { should render_template :index }

  describe '#show.json' do
    before { get :show, id: 1, format: :json }

    it { should render_template :show }

  describe '#collection' do
    before { expect(Product).to receive(:all) }

    it { expect { subject.send :collection }.to_not raise_error }

  describe '#resource' do
    before { expect(subject).to receive(:params).and_return({ id: 1 }) }

    before { expect(Product).to receive(:find).with(1) }

    it { expect { subject.send :resource }.to_not raise_error }

Not a surprise they don’t run now. Create a file app/controllers/api/products_controller.rb. and write a code there: 

    class Api::ProductsController < ApplicationController
     def collection
       @products ||= Product.all

     def resource
       @product ||= Product.find params[:id]

 Add one line of code to ApplicationController from which our new controller is inherited.

    class ApplicationController < ActionController::Base

     helper_method :resource, :collection


Having done this we can call methods resource and collection directly from views. No need to write action methods index and show. They are kept in the ActionController::Base from which all other controllers are inherited. They render templates with their names by default which is exactly what we need.

Now, we have to create templates,  where the most interesting part begins. All the templates (views) will be the same, even when we add a shopping cart and orders. They will look like those for the products. That is why we need to learn about the inheritance of views in Ruby on Rails.

All of them are inherited from the application, which in our case means that Ruby on Rails will look for templates in the directory app/views/application, if it doesn’t find them in the directoryapp/views/api/products. If it doesn’t find them in the latter one as well, you will see an error.

So let’s place the templates in the views/application directory. Create two files index.json.erband show.json.erb. They should be in the json format because the API of the shop will transfer data in it. Add this code to index.json.erb

     <%= sanitize collection.to_json %>  

 And, to show.json.erb:

     <%= sanitize resource.to_json %>  

Done. Let’s check the performance of the newly written API for the products. Launch the tests first and make sure they run smoothly. If not, you have done something wrong.  

Now, we have to check the API performance with the help of the curl command in the console. Let’s add a few products to the database. Run the console command rails console and write, for example: 

    Product.create!([{ name: 'apple', price: 5, description: 'green' },
                    { name: 'beer', price: 10, description: 'cold' }])  

The create! method will show an error if you do something wrong.

This code will enter two products in the database. Let’s make a request to the API with the curl command (don’t forget to launch a local server in the console with the rails server command). Write the following command in the console:

     curl -H "Accept: application/json" "http://localhost:3000/api/products"  

This should show the data of the products we have worked on.

Let’s check the show action.

     curl -H "Accept: application/json" "http://localhost:3000/api/products/1"  

It shows information about the product with id = 1.

Great! The products API works fine but it displays unnecessary information such as time when the product was created (created_at) or when it was updated (updated_at).

Let’s think how we can change it without transferring the parameter (only: [:id, :name, :price, :description]) to the to_json method.

We should keep in mind that all templates are the same for the whole app and there will be no such fields in another model. So, what should we do?

Connect the gem 'draper'. You can read about it here: https://github.com/drapergem/draper.

Let’s create a new decorator app/decorators/product_decorator.rb and write the code there:

    class ProductDecorator < Draper::Decorator

     def as_json *args
        id: id,
        name: name,
        price: price,
        description: description

You will probably ask why the method is named as_json if we call to_json in a template. Everything is very simple if you take a closer look at how the to_json method works in the original code: as_json is called within it. If you redefine this method with the necessary hash you will get the data needed.

Don’t forget to call the decorate method in templates:

In index.json.erb:

    <%= sanitize collection.decorate.to_json %>

 In show.json.erb:

     <%= sanitize resource.decorate.to_json %>  

 You should also remember to write tests for the decorator in the filespec/decorators/product_decorator.rb.

     require 'rails_helper'

   describe ProductDecorator do
     describe '#as_json' do
       let(:product) { stub_model Product, id: 1, name: 'apple', price: 10.0, description: 'green' }

       subject { product.decorate.as_json }

       its([:id]) { should eq 1 }

       its([:name]) { should eq 'apple' }

       its([:price]) { should eq 10.0 }

       its([:description]) { should eq 'green' }

Check if the tests have run properly and make requests again with the curl command (don’t forget to restart the server as we have just added new files to the app). You should see the data you need on the screen.   

And, what if a request to show action has an id that does not exist in the database? Then type the following in the code line in the app/controllers/api/products_controller.rb file:

     @product ||= Product.find params[:id]  

The find method will raise ActiveRecord::RecordNotFound exception and it will render the 404 error. To display this error in the json format add it to the ApplicationController that will handle this exception and render the exception.json.erb. template. 

    class ApplicationController < ActionController::Base

     rescue_from ActiveRecord::RecordNotFound do |exception|
       @exception = exception

       render :exception


 Let’s create views/application/exception.json.erb and write the code there:

    <%= sanitize({ errors: { @exception.class.name => [@exception.to_s] } }.to_json) %>  

Try to use the curl command to make a request to API for a product with an id that does not exist in the database. Let it be 4 for example: 

    curl -H "Content-Type: application/json" "http://localhost:3000/api/products/4"  

 You will see the following error description on the screen:

     "errors": {
       "ActiveRecord::RecordNotFound": [
         "Couldn't find Product with 'id'=4"

API for the e-commerce product is successfully completed. Well done!

Not bad for a beginner, but that's all for today. Next time we will unveil the second part of the "recipe" that will deal with searching products using Full Text Search in PostgreSQL. Don’t miss it! 


Ruby on Rails E-commerce API on GitHub

MLSDev Blog: 

Ruby on Rails E-commerce API for Beginners — Part 1

Ruby on Rails E-commerce API for Beginners — Part 2

Ruby on Rails E-commerce API for Beginners — Part 3

rails web development ,ruby on rails ,web dev ,rails ,beginner

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}