Rails Cheatsheet

by Giang, last updated 04 Feb 2020

Table of Content

Migration

Column data types

# Standard
:binary
:boolean
:date
:datetime
:decimal
:float
:integer
:bigint
:primary_key
:references
:string
:text
:time
:timestamp

# Extra native data types for Postgres:
:hstore
:json / :jsonb
:array
:cidr_address
:ip_address
:mac_address

# and more
# @see http://stackoverflow.com/q/17918117

Change existing table:

add_column :products, :price, :decimal, precision: 5, scale: 2
change_column :products, :quantity, :integer
# change column type from string to integer with Postgres
change_column :products, :price, 'integer USING CAST(price AS integer)'
remove_column :products, :photo, :string
rename_column :products, :image, :photo
change_column_default :advertisements, :enable, from: true, to: false
drop_table :products

Migrate and Rollback

rake db:migrate
rake db:rollback

Partial index with Postgres:

add_index :users, :is_active, where: "is_active = true"

Using bulk: true option when change table:

# before
def up
  add_column :table, :useful_foreign_key, :integer
  add_index :table, :useful_foreign_key
  add_column :table, :summary, :string
end

# after
def up
  change_table :table, bulk: true do |t|
    t.integer :useful_foreign_key
    t.index   :useful_foreign_key
    t.string  :summary
  end
end

Change json to json_b

def up
  change_column :posts, :meta_data, "jsonb USING avatar::JSONB", default: {}, null: false
end

def dowm
  change_column :posts, :meta_data, "jsonb USING avatar::JSON", default: {}, null: false
end

Validation

Builtin Validators

class Player < ApplicationRecord
  validates :terms_of_service, acceptance: true

  validates :name, :address, presence: true
  validates :password, confirmation: true

  # numericality validation does not allow nil value
  # use allow_nil: true to permit it
  validates :points, numericality: true
  validates :games_played, numericality: { only_integer: true }
  # other options:
  # :greater_than
  # :greater_than_or_equal_to
  # :equal_to
  # :less_than
  # :less_than_or_equal_to
  # :other_than
  # :odd
  # :even
end

Custom validators

These custom validators should be placed in app/validators

# validate object as a whole
class MyValidator < ActiveModel::Validator
  def validate(record)
    unless record.name.starts_with? 'X'
      record.errors[:name] << 'Need a name starting with X please!'
    end
  end
end

class Person < ActiveRecord::Base
  validates_with MyValidator
end
# validate attribute
class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
      record.errors[attribute] << (options[:message] || "is not an email")
    end
  end
end

class Person < ActiveRecord::Base
  validates :email, presence: true, email: true
end

Custom validation methods

class Event < ApplicationRecord
  validate :start_date_must_be_before_end_date

  private

  def start_date_must_be_before_end_date
    if start_date > end_date
      errors.add(:base, "start date must be before end date")
    end
  end
end

Resources