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.

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

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 you can’t.

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.

 

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"}
end

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.

en:
  activerecord:
    attributes:
      shipment:
        delivery_option:
          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', '');
SQL
end
end
end

 Validation

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.

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.