Skip to content

Instantly share code, notes, and snippets.

@rstacruz
Last active November 3, 2023 09:56
Show Gist options
  • Save rstacruz/1569572 to your computer and use it in GitHub Desktop.
Save rstacruz/1569572 to your computer and use it in GitHub Desktop.
Rails models cheatsheet

Rails Models

Generating models

$ rails g model User

Associations

belongs_to
has_one
has_many
has_many :through
has_one :through
has_and_belongs_to_many

belongs_to :author,
  class_name: 'User',
  dependent: :destroy  // delete this

Has many

has_many :comments, :order => "posted_on"
has_many :comments, :include => :author
has_many :people, :class_name => "Person", :conditions => "deleted = 0", :order => "name"
has_many :tracks, :order => "position", :dependent => :destroy
has_many :comments, :dependent => :nullify
has_many :tags, :as => :taggable
has_many :reports, :readonly => true
has_many :subscribers, :through => :subscriptions, :source => :user
has_many :subscribers, :class_name => "Person", :finder_sql =>
    'SELECT DISTINCT people.* ' +
    'FROM people p, post_subscriptions ps ' +
    'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' +
    'ORDER BY p.first_name'

Many-to-many

If you have a join model:

class Programmer < ActiveRecord::Base
  has_many :assignments
  has_many :projects, :through => :assignments
end

class Project < ActiveRecord::Base
  has_many :assignments
  has_many :programmers, :through => :assignments
end

class Assignment
  belongs_to :project
  belongs_to :programmer
end

Or HABTM:

has_and_belongs_to_many :projects
has_and_belongs_to_many :projects, :include => [ :milestones, :manager ]
has_and_belongs_to_many :nations, :class_name => "Country"
has_and_belongs_to_many :categories, :join_table => "prods_cats"
has_and_belongs_to_many :categories, :readonly => true
has_and_belongs_to_many :active_projects, :join_table => 'developers_projects', :delete_sql =>
"DELETE FROM developers_projects WHERE active=1 AND developer_id = #{id} AND project_id = #{record.id}"

Polymorphic associations

class Post
  has_many :attachments, :as => :parent
end

class Image
  belongs_to :parent, :polymorphic => true
end

And in migrations:

create_table :images do |t|
  t.references :post, :polymorphic => true
end

Migrations

Run migrations

$ rake db:migrate

Migrations

create_table :users do |t|
  t.string :name
  t.text   :description

  t.primary_key :id
  t.string
  t.text
  t.integer
  t.float
  t.decimal
  t.datetime
  t.timestamp
  t.time
  t.date
  t.binary
  t.boolean
end

options:
  :null (boolean)
  :limit (integer)
  :default
  :precision (integer)
  :scale (integer)

Tasks

create_table
change_table
drop_table
add_column
change_column
rename_column
remove_column
add_index
remove_index

Associations

t.references :category   # kinda same as t.integer :category_id

# Can have different types
t.references :category, polymorphic: true

Add/remove columns

$ rails generate migration RemovePartNumberFromProducts part_number:string

class RemovePartNumberFromProducts < ActiveRecord::Migration
  def up
    remove_column :products, :part_number
  end
 
  def down
    add_column :products, :part_number, :string
  end
end

Validation

Validate checkboxes

class Person < ActiveRecord::Base
  validates :terms_of_service, :acceptance => true
end

Validate associated records

class Library < ActiveRecord::Base
  has_many :books
  validates_associated :books
end

Confirmations (like passwords)

class Person < ActiveRecord::Base
  validates :email, :confirmation => true
end

Validate format

class Product < ActiveRecord::Base
  validates :legacy_code, :format => { :with => /\A[a-zA-Z]+\z/,
    :message => "Only letters allowed" }
end

Validate length

class Person < ActiveRecord::Base
  validates :name, :length => { :minimum => 2 }
  validates :bio, :length => { :maximum => 500 }
  validates :password, :length => { :in => 6..20 }
  validates :registration_number, :length => { :is => 6 }

  validates :content, :length => {
    :minimum   => 300,
    :maximum   => 400,
    :tokenizer => lambda { |str| str.scan(/\w+/) },
    :too_short => "must have at least %{count} words",
    :too_long  => "must have at most %{count} words"
  }
end

Numeric

class Player < ActiveRecord::Base
  validates :points, :numericality => true
  validates :games_played, :numericality => { :only_integer => true }
end

Non-empty

class Person < ActiveRecord::Base
  validates :name, :login, :email, :presence => true
end

custom

class Person < ActiveRecord::Base
  validate :foo_cant_be_nil

  def foo_cant_be_nil
    errors.add(:foo, 'cant be nil')  if foo.nil?
  end
end

API

items = Model.find_by_email(email)
items = Model.where(first_name: "Harvey")

item = Model.find(id)

item.serialize_hash
item.new_record?

item.create     # Same an #new then #save
item.create!    # Same as above, but raises an Exception

item.save
item.save!      # Same as above, but raises an Exception

item.update
item.update_attributes
item.update_attributes!

item.valid?
item.invalid?

http://guides.rubyonrails.org/active_record_validations_callbacks.html

Mass updates

# Updates person id 15
Person.update 15, name: "John", age: 24
Person.update [1,2], [{name: "John"}, {name: "foo"}]

Joining

Student.joins(:schools).where(:schools => { :type => 'public' })
Student.joins(:schools).where('schools.type' => 'public' )

Serialize

class User < ActiveRecord::Base
  serialize :preferences
end

user = User.create(:preferences => { "background" => "black", "display" => large })

You can also specify a class option as the second parameter that’ll raise an exception if a serialized object is retrieved as a descendant of a class not in the hierarchy.

class User < ActiveRecord::Base
  serialize :preferences, Hash
end

user = User.create(:preferences => %w( one two three ))
User.find(user.id).preferences    # raises SerializationTypeMismatch

Overriding accessors

class Song < ActiveRecord::Base
  # Uses an integer of seconds to hold the length of the song

  def length=(minutes)
    write_attribute(:length, minutes.to_i * 60)
  end

  def length
    read_attribute(:length) / 60
  end
end

Callbacks

after_create
after_initialize
after_validation
after_save
after_commit
@bernardo-cs
Copy link

very nice, thanks

@brunow
Copy link

brunow commented May 2, 2013

Thanks !

@degiorgig
Copy link

Great list of models features, I would maybe also mention the other way for the where cause:

Student.joins(:schools).where("schools.type = 'public'" )

@obelich
Copy link

obelich commented Oct 10, 2013

Thanks :)

@jcar787
Copy link

jcar787 commented May 15, 2014

Pretty nice!
Thanks

@goodbedford
Copy link

thanks you pretty darn good.

@rdhanaraj
Copy link

Tremendously useful.

@christru
Copy link

Awesome find thanks!

@schaary
Copy link

schaary commented Dec 14, 2014

nice, thx

@zx1986
Copy link

zx1986 commented Dec 14, 2014

WOW! Oorah!

@cah-jackson-gilman
Copy link

Just starting to learn how to use ActiveRecord and new to Ruby in general. This is extremely useful! Thanks!

@rstacruz
Copy link
Author

A more updated version of this cheatsheet is available here:

http://ricostacruz.com/cheatsheets/rails-models.html

@lcezermf
Copy link

Nice job man!

@sriram15690
Copy link

very nice

@techsin
Copy link

techsin commented Oct 27, 2015

what about 'delegate'

@Bengals10
Copy link

Bengals10 commented May 18, 2016

very nice!!!

+1 for your collection as well

@FrankFang
Copy link

presence: true                    # nil and empty string fail validation
presence: true, allow_blank: true # nil fails validation, empty string passes

@rahuldstiwari
Copy link

Thanks :)

Copy link

ghost commented Apr 4, 2017

nice!

@Bratela
Copy link

Bratela commented Aug 20, 2017

Good, thank you !

@jcPOLO
Copy link

jcPOLO commented Oct 5, 2017

thanks

@romerobrjp
Copy link

Very useful! Thank you!

@tuffs
Copy link

tuffs commented Mar 4, 2019

B-e-a-utiful!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment