Rails: Reinstall all gems again

I was messing with a gem in my ruby on rails and ended up deleting all the installed gems manually on my local machine while experimenting.

I tried to reinstall using `bundle` which did not help as it thinks that gems are already installed looking at the `Gemfile.lock` file.

After googling a little bit I found bundle install --force to forcefully reinstall all of them.

Happy coding!

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
  • 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,
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])

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.


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?


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

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.

Rails: Kick a logged in user(devise) out of his session: solved

Have you ever thought of kicking a specific logged in user out of their session (for some weird reason).

If you are using devise for authentication then the short answer is no/yes. Read through the rest of the the post for explanation or scroll to the last for a hacky way.

I tried many ways to hack around to fool devise into thinking that the user session is expired but no luck. The user session cannot be accessed by other users (like from the rails console or database level).

The closest i thought I came is to trick the Timeoutable  hook. But it depends on last_request_at which is taken from the user session.  I tried messing with db fields like

current_sign_in_at, last_sign_in_at but realized that devise does not look at these fields once the user logs in.

Over all, the conclusion is that we can’t mess around with Devise which does its job well.

Note: You can still clear all the sessions for all the users using the following ways, depending on where you stored the session :

  1. Cookie Store (default) :

    Fleet::Application.config.session_store :cookie_store, key: _change_me_session.

    When you change the key the old sessions expire.

  2. Redis as session store: redis-cli flushall or delete sessions using a wildcard if we know part of the key $redis.del $redis.keys('session*').
  3. Database: If the sessions are stored in the database rake db:sessions:clear.

Update: Hacky way: After all this efforts I found out that we don’t even need to break our head to crack devise. Just change the `password` of the `user` from rails console and that will log him out.  I called it a hacky way as the user can not login again with previous password (can revert it back to normal after logout though).


Rails: can not be used with :count => 1. key ‘one’ is missing.

If you ever encountered this error probably you are trying to add/access a I18n key for a `enum` attribute. For example if my model has a `enum` value like below.

class Shipment < ApplicationRecord
   enum delivery_option: {"arrival_notice":"arrival_notice", "arrival_schedule": "arrival_schedule"}

If we want to internationalize the `values` as

Call/notify before delivery and Delivery appointment required

. In your en.yml you need to specify as below.

          one: 'Delivery Option'
          arrival_notice: "Call/notify before delivery"
          arrival_schedule: "Delivery appointment required"

I18n expects the name of-the field as the first key/value.If you forget that then you see this error. Happy coding!

Update and Validate a rails hstore column

Rails Update hstore column

For example if i have a hstore column like below

settings public.hstore DEFAULT '"currency"=>"USD"'::public.hstore NOT NULL,

Now I will update the column to add preferences in a migration as below

class AddPreferencesToUser < ActiveRecord::Migration[5.1]
  def change
    reversible do |dir|
      dir.up do
        update <<-SQL
          UPDATE users SET settings = settings || hstore('preferences', '');


Assume we want to validate preferences to be one of  facebook, twitter, linkedin these.

the validation looks this. as enum doesn’t work with hstore key well.

store_accessor :preferences validates :preferences, inclusion: ['facebook', 'twitter', 'linkedin'], allow_blank: true

see you next time!

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.