self joins

class Employee < ApplicationRecord
  has_many :subordinates, class_name: Employee.name, foreign_key: :manager_id
  belongs_to :manager, class_name: Employee.name
end

Migration

class CreateEmployees < ActiveRecord::Migration[5.0]
  def change
    create_table :employees do |t|
      t.references :manager, foreign_key: true
      t.string :name

      t.timestamps
    end
  end
end

controlling caching

Rails keeps result of most recent query available for further operation.

author.books # query
author.books.size # cache
author.books.empty? # cache

Use reload function to reload cache

name collision

Creating a association adds a new method to model, It’s a bad idea to give association a name that already used for instance methods of ActiveRecord::Base. Association method would override the base method and breaks thing.

updating schema

class Author < ApplicationRecord
  has_many :books
end 

class Book < ApplicationRecord
  belongs_to :author
end

You need to backed up by proper foreign key declaration on then books table:

class CreateBooks < ActiveRecord::Migration[5.0]
  def change
    create_table :books do |t|
      t.datetime :published_at
      t.string   :book_number
      t.integer  :author_id
    end
  end
end

It’s good practice to add an index on the foreign key to improve queries performance

class CreateBooks < ActiveRecord::Migration[5.0]
  def change
    create_table :books do |t|
      t.datetime :published_at
      t.string   :book_number
      t.integer  :author_id
    end
 
    add_index :books, :author_id
    add_foreign_key :books, :authors
  end
end

inverse_of

Normal association:

class Author < ApplicationRecord
  has_many :books
end

class Book < ApplicationRecord
  belongs_to :author
end

bi-directional association Active Record will load only one copy of Author object, makes application more efficient

a = Author.first
b = a.books.first
a.equal? b.author #true

However, Active Record will not automatically identify bi-directional associations that contain any of following options:

  • conditions
  • class_name
  • through
  • polymorphic
  • foreign_key
a = Author.first
b = a.books.first
a.equal? b.author #false

Active Record provides :inverse_of keyword, you will explicitly declare bi-directional association

class Author < ApplicationRecord
  has_many :books, inverse_of: :writer
end 

class Book < ApplicationRecord
  belongs_to :writer, class_name: Author.name, foreign_key: :author_id
end
a = Author.first
b = a.books.first
a.equal? b.writer # true