Adding devise_token_auth to an existing Rails app

Ruby on rails is still the frontrunner for getting an MVP(minimum viable product) out of the door. Eventual when things go our way we want to introduce F/E framework on the customer facing side for various reasons(continue using the admin part as traditional rails app). If you are already using devise and wondering how to use it for api calls this post is for you.

The devise_token_auth is a gem on top of devise which works with tokens and leverages on devise. We can even configure it to either refresh the token for every single request or not.

Without further delay let’s jump in.

Add the following to your Gemfile. We need rack-cors to get support for Cross-Origin Resource Sharing (CORS).

gem ‘devise_token_auth’

gem rack-cors

Then install the gem using bundle:

bundle install

Assuming we are using User model run the following command to prepare for the setup.

rails g devise_token_auth:install User auth

This is going to generate the following files

create  config/initializers/devise_token_auth.rb
insert  app/controllers/application_controller.rb
gsub  config/routes.rb
create  db/migrate/20190712184641_devise_token_auth_create_users.rb
insert  app/models/user.rb

So far we have done exactly as mentioned in the docs which thinks there is no devise functionality already implemented.

As we want new token implementation to work on top of our existing admin side(traditional rails app using devise) do the following changes.

  • routes.rb: Move mount_devise_token_auth_for User, at: auth into api routes. As we only want this routes to be used in the context of api.
 mount_devise_token_auth_for 'User', at: 'auth'
namespace :api do
  namespace :v1 do
    mount_devise_token_auth_for 'User', at: 'auth', defaults: {format: 'json'}
  • application_controller.rb:                                                                                                Remove include DeviseTokenAuth::Concerns::SetUserByToken from application_controller.rb and move to your api base controller. Else this will mess up with your devise authentication.
class Api::V1::BaseController
  include DeviseTokenAuth::Concerns::SetUserByToken
  • Rename migration to xxx_devise_token_auth_update_users and make sure you remove all the existing devise module columns which you already have.
class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[5.2]   def change     change_table(:users) do |t|       ## Required       t.string :provider, :null => false, :default => "email"
      t.string :uid, :null => false, :default => ""
      t.boolean  :allow_password_change, default: true

      ## Tokens
      t.json :tokens
    end
  end
end
  • User.rb: Remove the modules you already included. I don’t need omniauth at this moment so i removed it.
# Include default devise modules.
devise :database_authenticatable, :registerable,
        :recoverable, :rememberable, :trackable, :validatable,
        :confirmable
include DeviseTokenAuth::Concerns::User

Apart from the above i made the following changes to make it work.

class Api::V1::BaseController < JSONAPI::ResourceController
  include DeviseTokenAuth::Concerns::SetUserByToken

before_action :configure_permitted_parameters, if: :devise_controller?

def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_in, keys: [:email, :password])
end

In application_controller.rb

class ApplicationController < ActionController::Base

protect_from_forgery with: :exception
protect_from_forgery with: :null_session, if: -> { request.format.json? }

 wrap_parameters false

In development.rb

resource '*', headers: :any,
         expose: %w(etag access-token uid expiry token-type client Rate-Search-Uuid),
         methods: [:get, :post, :delete, :put, :patch, :options, :head]

Now you can send a curl command like below.

curl -X POST http://localhost:3000/api/v1/auth/sign_in
-H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'cache-control: no-cache' \
  -H 'content-type: multipart/form-data;
  -F email=email@company.com \
  -F password=password

The success response consists of access_token, uid, client from headers. Don’t forget to send these back and forth on the consecutive requests.

Drop comments if you are stuck or have any concerns.

Thanks!

Ruby singleton_class

Let’s learn about singleton_class with an example. I have a Car which knows to drive.

class Car
  def drive
    puts "I am driving"
  end
end

car = Car.new
car.drive # I am driving

Cool so what! Now at later point of time I want to add honk to my car only when it is stuck in traffic. I don’t want it to be added for every Car object.

There might be more than one way of doing this in ruby but in the interest of this post i will implement this with singleton_class.  Ruby singleton_class inserts a new anonymous class into the inheritance hierarchy as a container and adds the new method to it.

class Car
  def drive
    puts "I am driving"
  end
end

module Honking
  def honk
    puts "Get away on my way"
  end
end

car = Car.new

traffic = true # more logic here

if traffic
  car.singleton_class.include(Honking)  
end

car.honk

p car.singleton_methods # [:honk]

race_car = Car.new
race_car.honk # undefined method `honk'

singleton_class creates a new singleton class if car does not have one. From then what ever changes you make on that is going to be affected to that particular class. Thats the reason race_car doesn’t know anything about honk.

I also used singleton_classto add additional validations to the object in a specific context.

You can check singleton methods on a class using singleton_methods.

Happy coding!

Ruby mixins explained

Hi Devs,

In this post i will try to explain how to use ruby mixins for DRYing up your code. Let’s say I have Car which can drive and honk. It can find a car with vin number or return count.

class Car
  def self.find(vin)
    puts "return car with VIN number #{vin}"
  end

  def self.count
    puts "return number of cars"
  end
  def honk
    puts "I like to yell at people"
  end

  def drive
    puts "will try to avoid speed tickets"
  end
end

# A Car can drive, honk

car = Car.new
car.drive
car.honk

# Find car by its VIN number
Car.find("123")
# Get total number of cars
Car.count

Now we get a requirement to add Trucks to our inventory which do most of the things aCar does. Let’s start DRYing the code.

First I will extract instance methods using a module and use include to make them available. In ruby we use include to add instance level methods from a module.

module VehicleBehavior
  def honk
    puts "I like to yell at people"
  end

  def drive
    puts "will try to avoid speed tickets"
  end
end

class Car
  include VehicleBehavior

  def self.find(vin)
    puts "return car with VIN number #{vin}"
  end

  def self.count
    puts "return number of cars"
  end
end

Making progress. Now i will extract the class level methods into a module and use theextend keyword to make them available. In ruby we use extend to add class level methods from a module.

module VehicleBehavior
  def honk
    puts "I like to yell at people"
  end

  def drive
    puts "will try to avoid speed tickets"
  end
end

module VehicleData
  def self.find(vin)
    puts "return car with VIN number #{vin}"
  end

  def self.count
    puts "return number of cars"
  end
end

class Car
  include VehicleBehavior
  extend VehicleData
end

Good. But is there a way to combine both modules into one ? yes.

Every time a class includes module – Ruby will trigger the self.included method on that module. It will also pass class as a parameter. In our case the Car class will be the klass argument.

module Vehicle
  def self.included(klass)
    klass.extend(ClassMethods)
  end

  module ClassMethods
    def find(vin)
      puts "return car with VIN number #{vin}"
    end

    def count
      puts "return number of cars"
    end
  end

  def honk
    puts "I like to yell at people"
  end

  def drive
    puts "will try to avoid speed tickets"
  end
end

class Car
  include Vehicle
end

Looking good. But is there is a cleaner way to do this YesActiveSupport::Concern

require 'active_support/concern'

module Vehicle
  extend ActiveSupport::Concern

  def honk
    puts "I like to yell at people"
  end

  def drive
    puts "will try to avoid speed tickets"
  end

  class_methods do
    def find(vin)
      puts "return car with VIN number #{vin}"
    end

    def count
      puts "return number of cars"
    end
  end
end

class Car
  include Vehicle
end

car = Car.new

Car.find("blah")
car.drive
car.honk

ActiveSupport::Concern makes the syntax better and also has the advantage of  gracefully handling module dependencies.

Now our Truck class is as simple as this

class Truck
  include Vehicle
end

Pretty cool right? Less code! Less bugs!! YaY.

Rails date validation pit falls

When ever you want to validate a date field against a time frame don’t forget to add context to it. For example I have the following class

Movie – name, release_date and collections

class Movie
  validates :release_date, presence: true
  validate :release_date_future?

  private

  def release_date_future?
    if release_date < Date.today
      errors.add(:release_date, "can't be in the past")
    end
  end
end

This Class looks absolutely legit. Let’s say I have a Movie object called Avengers endgame.

Movie.new(name: ‘Avengers endgame’, release_date: ’04-26-2019′).save

So far so good but when i want to update the `collections` at later point of time(after the movie got released) i can never do that because the Movie obj goes invalid (as it once again checks the release_date with current_date).

so the right thing to do is to add context to the date validation. Like we are interested in only while creation.

validate :release_date_future?, on: :create

Hope this helps.

Java vs Ruby

Runtime differences:

In Java the program always starts with a main method. Ruby program by default creates a main Object which is an instance of class class and then starts execution on it(weird!). It always starts reading from the first line of the file, there is no specific starting point.

So when you create a ruby test file HelloWorld.rb with below statement

puts "HelloWorld"

execute it in terminal with ruby HellowWorld.rb . Ruby interpreter creates main object and then starts to execute puts.(puts is an instance method from kernel module. These methods are called without a receiver).

To test this go to terminal irb and do the following.

ruby main object

Execution differences:

Java is a compiled language so the execution is a 2 step process. compile + run.

Ruby is an interpreting language.

Both Java compiler and Ruby interpreter are written in C.

Programatic differences:

Ruby is completely object oriented what does that mean from a java perspective ?

– In java we have primitive data types such as int, float etc along with Classes and Objects. In Ruby Integer, Float etc are also Classes inherited from Numeric class which intern inherited from Object class. here is a detailed image taken from rubylearning.com which explains this.

class

So when you create an Integer in ruby you are creating a object for Integer class.

One more important ruby feature to discuss is duck typing.

Java is strictly or strongly typed language where we need to declare the type of variable.

Ruby has implicit and explicit type conversions.

Lets see what implicit conversion means.

duck typing

Ruby is loosely typed language where it tries to define the type of a variable implicitly as shown above. If it can not infer it it throws an error as below.

undefined local variable or method

Explicit conversion is kind of ruby’s way to type safety. I can try to convert into my expected type. see below.

ruby convert to string

Happy coding!

 

Difference between string and symbol in ruby

Ruby symbol and string does the same thing except symbol is more efficient in terms of memory and time.

As explained here

Symbol is the most basic Ruby object you can create. It’s just a name and an internal ID. Symbols are useful because a given symbol name refers to the same object throughout a Ruby program. Symbols are more efficient than strings. Two strings with the same contents are two different objects, but for any given name there is only one Symbol object. This can save both time and memory.

ruby string symbol

Therefore, when do we use a string versus a symbol?

  • If the contents (the sequence of characters) of the object are important, use a string
  • If the identity of the object is important, use a symbol.

We can change them to each other like this

puts “string”.to_sym.class # Symbol

puts :symbol.to_s.class    # String

Symbols are particularly useful when creating hashes and you want to have a distinction between keys and values.

Rails migrations best practices

Avoid using Rails models in migration.

Reasons:

  1. Models might have some lifecycle callbacks which we dont want to be invoked in a migration.
  2. As we know what we are doing we dont want to deal with validations.
  3. Model names can change irrespective of db table.
  4. Try to use raw sql as close as possible.

Squash them after a period of time.

Reasons:

  1.  To my experience over a period of time these migration files are painful and useless.
  2. Every rake db:migrate might take a few seconds, or creating of a new database might take a few minutes when these files are big. Consider using tools like squasher.

Make them irreversible.

Reason:

In Production it makes sense to have IrreversibleMigration as the code is tested in lower environments. If there is an issue try to fix it with a follow up migration.

Note: If there is a new developer in your team and setting up their environment. Let them do `rake db:schema:load` to get latest db copy.