How to Build an eCommerce API With Ruby on Rails Part 3

This article was prepared by a guest contributor to ProgrammableWeb. The opinions expressed in this article are the author's own and do not necessarily reflect the view of ProgrammableWeb or its editorial staff.

This is the final part of our Ruby on Rails development kitchen. We hope you are eager to learn the next part of the recipe. As usual, you won’t need any dishes, spoons or knives. Just your computer and you, ready to code and create.

A small reminder for those who missed the first and the second parts of our tutorial: don’t forget to read them first.

The third part is devoted to registration and authorization. Every e-commerce platform needs them so we cannot skip this important requirement too. Safe online shopping is essential and has to be as private and convenient as possible. Let’s start with the registration. To begin with, create the model User with such fields as name:string, email:string, password_digest:string. To do this run the following command in the console:

$ rails generate model User name email password_digest

Then remember to run another command:

$ rake db:migrate

Go to the file app/models/user.rb and add the code line:

class User < ActiveRecord::Base
has_secure_password
end

Let’s analyze the has_secure_password method in detail. It is used for saving a password, its validation and encryption (a cryptographic hash-function BCrypt is used for it). This method works with the field password_digest that is why we named it so. has_secure_password automatically connects 3 validations:

A password has to be entered while creating.

The password length has to be equal to or less than 72 symbols.

The password confirmation (the attribute password_confirmation is used for that).

For the correct work of has_secure_password you need to connect the bcrypt gem. Go to Gemfile and add the following there:

gem 'bcrypt'

Don’t forget about the command:

$ bundle install

Let’s also add validations to the fields name and email. We will use the email_validator gem for the email validation. Its description can be found here: https://github.com/balexand/email_validator. Connect it and write validations in the model User.

require 'rails_helper'
RSpec.describe User, type: :model do
it { should have_secure_password }
it { should validate_presence_of :name }
it { should validate_presence_of :email }
it { should validate_uniqueness_of(:email).case_insensitive }
it { should_not allow_value('test').for(:email) }
it { should allow_value('test@test.com').for(:email) }
end

As the next step you need to create UserDecorator and write the method #as_json there to make correct data return in the answer to this request. We already did the same in the first part of the tutorial when creating products.

Done. The registration is completed and we can move to the next point of our today’s task and create authorization for our users. We will use Token-Based Authentication to do that (there is a lot of information about it online).

At first we need to create the AuthToken model with the field value:string and with the external key user_id. We will store user tokens here. Run the following command in the console:

$ rails generate model AuthToken

Then go to the migration file (timestamp)_create_auth_tokens.rb and write:

It means that we have defined the one to one connection for the models User and AuthToken. The dependent option with the destroy value means that when deleting a user record from the database a connected record from the auth_tokens table will be deleted too.

Add validation for auth_token as well and then write tests for the AuthToken model:

require 'rails_helper'
RSpec.describe AuthToken, type: :model do
it { should belong_to :user }
it { should validate_presence_of :value }
end

Continue with adding the test to the User model:

it { should have_one(:auth_token).dependent(:destroy) }

As the next step, create the singleton resource api/session with the action #create #destroy. Go to config/routes.rb:

Rails.application.routes.draw do
namespace :api do
...
resource :session, only: [:create, :destroy]
end
end

Before creating SessionsController, we need to create the class Session, where a token for a new version will be generated and the session validation will be performed. Place this class in the /lib directory. To do this, we need to write the way for file uploading in config/application.rb.

Let’s analyze the code. The constructor (method initialize) accepts hash as a parameter and records to instance such variables as @email, @user and @password. Two getter methods (email and password) are also defined in the line:

attr_reader :email, :password

The ActiveModel::Validations allows us to use validations in this class. The following methods are connected: errors, invalid?, valid?, validate, validates_with.

The user search by email is done in the #user method. If it is successful, @user is recorded in instance, if nothing is found, then it is nil. We need to check the validation to make sure if there is such a user with the email and if the entered password is correct.

If a user is not valid, the #save! method returns the ActiveModel::StrictValidationFailed error. Otherwise a new token is created. The #destroy! method deletes the user token. The #auth_token method returns the token value.

Let’s define the #as_json and #decorate methods instead of using the decorator. We need to cover this class with the spec/lib/session_spec.rb tests.

Don’t forget that the actions #create and #destroy are defined in ApplicationController. In the #resource method, current_user is the object of the User class of a current user. We will tell you about its creation later.

So, a user of our online-shop can create a new session now. But how can we check it in the requests that ask for authorization? API RoR can help (the authenticate_or_request_with_http_token method if to be more precise). This method calls two other methods inside of itself: authenticate_with_http_token and request_http_token_authentication. You'll authenticate_with_http_token parses http header with the name Authorization and returns the token value. After that we need to do the token search in the database inside of the block of this method. The header should look the following way:

"Authorization: Token token="value"" Authorization - header name.

Token means that the authorization is Token-Based.
token="" is an attribute with the token value.
The request_http_token_authentication method will render Error 401 with the text “HTTP Token: Access denied.” if the authenticate_with_http_token method returns nil.
Go to ApplicationController and add:

Now all API requests ask for authorization i.e. token transferring. But, for example, a request for a session creation shouldn’t require authorization. We need to correct it. Go to SessionsController and add:

If you have done everything right you will see a generated token on the screen. Copy it as we will need it for further requests. Let’s try to make a request that requires authorization without transferring a token.

If processed successfully, this request will return an empty body with the status 200. If you try to repeat it you will see the text "HTTP Token: Access denied." because the token has been deleted from the database.

Seems like this is it for now. The tasks have been accomplished. We have done the registration and authorization for the online-shop. You are moving in the right direction and your e-commerce project is getting bigger.

This part of the series has been republished with permission from MLSDev. The original article can be seen here.

About the author:Yuriy Blokhin
I am a Ruby on Rails Developer at MLSDev Inc. - one of the Top European IT companies specializing in mobile and web apps development, UI/UX and consulting.