Skip
Arish's avatar

21. Active Record Basics


Active Record Basics

Active Record is Rails' ORM (Object-Relational Mapping) that connects your Ruby objects to database tables. It makes database operations feel like working with plain Ruby objects.

What is Active Record?

Active Record follows the Active Record pattern where:

  • Each database table maps to a Ruby class
  • Each row in the table maps to an object of that class
  • Each column maps to an attribute of that object
ruby
1# Table: users
2# | id | name  | email           | created_at |
3# |----|-------|-----------------|------------|
4# | 1  | John  | john@email.com  | 2024-01-15 |
5# | 2  | Jane  | jane@email.com  | 2024-01-16 |
6
7# Ruby class
8class User < ApplicationRecord
9end
10
11# Object
12user = User.find(1)
13user.name   # => "John"
14user.email  # => "john@email.com"

Creating a Model

Using the Generator

bash
1rails generate model User name:string email:string age:integer active:boolean
2
3# Creates:
4# app/models/user.rb
5# db/migrate/xxx_create_users.rb
6# test/models/user_test.rb

The Model File

ruby
1# app/models/user.rb
2class User < ApplicationRecord
3  # Model code goes here
4end

The Migration File

ruby
1# db/migrate/20240115000000_create_users.rb
2class CreateUsers < ActiveRecord::Migration[7.1]
3  def change
4    create_table :users do |t|
5      t.string :name
6      t.string :email
7      t.integer :age
8      t.boolean :active, default: true
9
10      t.timestamps  # Adds created_at and updated_at
11    end
12  end
13end

Naming Conventions

Rails uses naming conventions to connect models to tables:

Model (Singular)Table (Plural)
Userusers
Articlearticles
Personpeople
LineItemline_items

Override with:

ruby
1class User < ApplicationRecord
2  self.table_name = "my_users"
3  self.primary_key = "user_id"
4end

CRUD Operations

Create

ruby
1# Method 1: new + save
2user = User.new
3user.name = "John"
4user.email = "john@example.com"
5user.save  # Returns true/false
6
7# Method 2: new with hash
8user = User.new(name: "John", email: "john@example.com")
9user.save
10
11# Method 3: create (new + save in one step)
12user = User.create(name: "John", email: "john@example.com")
13
14# Method 4: create! (raises exception on failure)
15user = User.create!(name: "John", email: "john@example.com")

Read

ruby
1# Find by ID
2user = User.find(1)           # Raises error if not found
3user = User.find_by(id: 1)    # Returns nil if not found
4
5# Find by attribute
6user = User.find_by(email: "john@example.com")
7user = User.find_by!(email: "john@example.com")  # Raises if not found
8
9# Find all
10users = User.all
11
12# Find with conditions
13users = User.where(active: true)
14users = User.where("age > ?", 18)
15users = User.where("name LIKE ?", "%John%")
16
17# First and last
18first_user = User.first
19last_user = User.last
20
21# Count
22User.count
23User.where(active: true).count

Update

ruby
1# Method 1: Find, modify, save
2user = User.find(1)
3user.name = "Jane"
4user.save
5
6# Method 2: update
7user = User.find(1)
8user.update(name: "Jane")
9
10# Method 3: update! (raises on failure)
11user.update!(name: "Jane")
12
13# Update all matching records
14User.where(active: false).update_all(active: true)
15
16# Update single attribute (skips validations)
17user.update_attribute(:name, "Jane")
18
19# Update column directly (skips callbacks and validations)
20user.update_column(:name, "Jane")

Delete

ruby
1# Delete a single record (runs callbacks)
2user = User.find(1)
3user.destroy
4
5# Delete by ID
6User.destroy(1)
7
8# Delete all matching
9User.where(active: false).destroy_all
10
11# Delete without callbacks
12user.delete
13User.delete(1)
14User.where(active: false).delete_all

Working with Records

Checking State

ruby
1user = User.new
2
3user.new_record?   # => true (not saved yet)
4user.persisted?    # => false
5
6user.save
7
8user.new_record?   # => false
9user.persisted?    # => true
10
11user.changed?      # => false
12user.name = "New Name"
13user.changed?      # => true
14user.name_changed? # => true
15user.changes       # => {"name"=>["John", "New Name"]}
16
17# Check if record exists
18User.exists?(1)
19User.exists?(email: "john@example.com")
20User.where(active: true).exists?

Reloading

ruby
1user = User.find(1)
2# Someone else updates the record in the database
3user.reload  # Refresh from database

Attributes

ruby
1user = User.find(1)
2
3# Get all attributes as a hash
4user.attributes
5# => {"id"=>1, "name"=>"John", "email"=>"john@example.com", ...}
6
7# Access attributes
8user[:name]
9user.name
10user.read_attribute(:name)
11
12# Set attributes
13user[:name] = "Jane"
14user.name = "Jane"
15user.write_attribute(:name, "Jane")
16
17# Assign multiple (doesn't save)
18user.assign_attributes(name: "Jane", email: "jane@example.com")
19user.save

Date and Time Columns

ruby
1# timestamps are automatically added
2class CreatePosts < ActiveRecord::Migration[7.1]
3  def change
4    create_table :posts do |t|
5      t.string :title
6      t.datetime :published_at
7      t.date :event_date
8      t.time :start_time
9      
10      t.timestamps  # created_at and updated_at
11    end
12  end
13end
14
15# Using date/time
16post = Post.create(
17  title: "My Post",
18  published_at: Time.current,
19  event_date: Date.today,
20  start_time: Time.current
21)
22
23post.created_at  # When created
24post.updated_at  # When last updated (auto-updated)

Touch

Update the updated_at timestamp:

ruby
1user.touch                    # Update updated_at to now
2user.touch(:last_login_at)    # Update specific timestamp column

Increment and Decrement

ruby
1# Increment counter
2article.increment(:views_count)
3article.increment!(:views_count)  # Saves immediately
4
5# Decrement
6product.decrement(:stock)
7product.decrement!(:stock)

Active Record makes database operations intuitive and Ruby-like!