Rails ActiveRecord Reference
ActiveRecord complete reference: migrations, associations, validations, callbacks, named scopes, and query interface patterns.
1. Migrations
# rails generate migration CreateArticles
class CreateArticles < ActiveRecord::Migration[7.1]
def change
create_table :articles do |t|
t.string :title, null: false, limit: 300
t.string :slug, null: false, index: { unique: true }
t.text :content, null: false
t.string :status, null: false, default: "draft"
t.boolean :featured, default: false
t.integer :view_count, default: 0
t.jsonb :metadata, default: {}
t.references :author, null: false, foreign_key: { to_table: :users }
t.datetime :published_at
t.timestamps
end
add_index :articles, :status
add_index :articles, [:author_id, :status]
add_index :articles, :published_at
end
end
# Add column
class AddRoleToUsers < ActiveRecord::Migration[7.1]
def change
add_column :users, :role, :string, default: "user", null: false
add_index :users, :role
end
end
2. Associations
class User < ApplicationRecord
has_many :articles, foreign_key: :author_id, dependent: :nullify
has_one :profile, dependent: :destroy
has_many :comments, through: :articles
end
class Article < ApplicationRecord
belongs_to :author, class_name: "User"
has_many :comments, dependent: :destroy
has_many :commenters, through: :comments, source: :user
has_and_belongs_to_many :tags
# Polymorphic
has_many :likes, as: :likeable, dependent: :destroy
end
class Comment < ApplicationRecord
belongs_to :article
belongs_to :user
end
class Like < ApplicationRecord
belongs_to :likeable, polymorphic: true
belongs_to :user
end
3. Validations
class Article < ApplicationRecord
validates :title, presence: true, length: { minimum: 5, maximum: 300 }
validates :slug, presence: true, uniqueness: true,
format: { with: /\A[a-z0-9\-]+\z/, message: "only lowercase letters, numbers, hyphens" }
validates :content, presence: true, length: { minimum: 50 }
validates :status, inclusion: { in: %w[draft published archived] }
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }, allow_blank: true
# Conditional
validates :published_at, presence: true, if: :published?
# Custom validator
validate :slug_not_reserved
private
def published?
status == "published"
end
def slug_not_reserved
reserved = %w[admin api auth login logout register]
errors.add(:slug, "is reserved") if slug.in?(reserved)
end
end
4. Callbacks
class Article < ApplicationRecord
before_validation :generate_slug, if: -> { slug.blank? }
before_save :sanitize_content
after_create :notify_subscribers
after_destroy :cleanup_cache
private
def generate_slug
self.slug = title.to_s.parameterize
end
def sanitize_content
self.content = ActionController::Base.helpers.sanitize(content, tags: %w[p b i a ul ol li])
end
def notify_subscribers
NotifySubscribersJob.perform_later(id) if published?
end
def cleanup_cache
Rails.cache.delete("article:#{id}")
end
end
5. Scopes & Query Interface
class Article < ApplicationRecord
scope :published, -> { where(status: "published") }
scope :featured, -> { where(featured: true) }
scope :recent, -> { order(created_at: :desc) }
scope :by_author, ->(user_id) { where(author_id: user_id) }
scope :search, ->(q) { where("title ILIKE ?", "%#{q}%") }
end
# Usage
articles = Article.published.featured.recent.page(1).per(20)
articles = Article.published.by_author(current_user.id).search("ruby")
# Query methods
Article.where(status: "published").order(created_at: :desc).limit(10)
Article.where("view_count > ?", 1000).pluck(:id, :title)
Article.includes(:author, :tags).where(tags: { name: "ruby" })
Article.left_joins(:comments).where(comments: { id: nil }) # no comments
# Aggregation
Article.published.count
Article.group(:status).count
Article.published.average(:view_count)
6. Migration Column Types
| Type | Ruby | SQL (PostgreSQL) |
|---|---|---|
| String | :string | CHARACTER VARYING(255) |
| Text | :text | TEXT |
| Integer | :integer | INTEGER |
| BigInt | :bigint | BIGINT |
| Boolean | :boolean | BOOLEAN |
| Float | :float | FLOAT |
| Decimal | :decimal | DECIMAL(p,s) |
| DateTime | :datetime | TIMESTAMP |
| JSON | :json / :jsonb | JSON / JSONB |
| UUID | :uuid | UUID |