Active Record入門:検索・更新・リレーションの基本まとめ

スポンサーリンク

Active Record入門:検索・更新・リレーションの基本まとめ

はじめに

Active RecordはRailsのORMで、Rubyのコードでデータベースを操作できます。SQLを直接書かなくても User.where(name: "田中") のように書けば、対応するSQLが自動で発行されます。

この記事では基本的なCRUD操作から、検索・リレーション・スコープまでまとめます。


セットアップ

モデルクラスは ApplicationRecord を継承して作ります。

# app/models/user.rb
class User < ApplicationRecord
end

Railsはテーブル名を自動で推測します。User モデルは users テーブルに対応します。

bin/rails generate model User name:string email:string
bin/rails db:migrate

基本のCRUD

Create — 作成

# new + save
user = User.new(name: "田中太郎", email: "tanaka@example.com")
user.save   # => true / false

# create(new + save を一括)
user = User.create(name: "田中太郎", email: "tanaka@example.com")

# create!(失敗時に例外を発生)
user = User.create!(name: "田中太郎", email: "tanaka@example.com")

発行されるSQL:

INSERT INTO "users" ("name", "email", "created_at", "updated_at")
VALUES ('田中太郎', 'tanaka@example.com', '2026-05-29', '2026-05-29')

Read — 検索

User.all                         # 全件
User.find(1)                     # IDで1件(なければ例外)
User.find_by(name: "田中太郎")   # 条件で1件(なければnil)
User.find_by!(name: "田中太郎")  # 条件で1件(なければ例外)
User.where(name: "田中太郎")     # 条件で複数件(Relation)
User.first                       # 最初の1件
User.last                        # 最後の1件
User.count                       # 件数

Update — 更新

user = User.find(1)

# update
user.update(name: "田中次郎")      # => true / false
user.update!(name: "田中次郎")     # 失敗時に例外

# 属性を変更してsave
user.name = "田中次郎"
user.save

# 一括更新(バリデーション・コールバックをスキップ)
User.where(active: false).update_all(deleted_at: Time.current)

発行されるSQL:

UPDATE "users" SET "name" = '田中次郎', "updated_at" = '2026-05-29' WHERE "id" = 1

Delete — 削除

user = User.find(1)
user.destroy   # コールバックあり
user.delete    # コールバックなし・SQLを直接発行

# 一括削除
User.where(active: false).destroy_all  # コールバックあり(N回SQL発行)
User.where(active: false).delete_all   # コールバックなし(1回のSQL)

検索

where

User.where(name: "田中太郎")
User.where(name: ["田中太郎", "鈴木花子"])          # IN句
User.where.not(name: "田中太郎")                   # NOT
User.where("created_at > ?", 1.week.ago)           # 文字列条件(プレースホルダ必須)
User.where("name LIKE ?", "%田中%")
User.where(active: true).where("age > ?", 20)      # AND条件(チェーン)

順序・件数

User.order(:name)                  # 昇順
User.order(created_at: :desc)      # 降順
User.order("created_at DESC, name ASC")
User.limit(10)
User.limit(10).offset(20)          # ページネーション

集計

User.count
User.where(active: true).count
User.maximum(:age)
User.minimum(:age)
User.average(:age)
User.sum(:point)
User.group(:role).count            # GROUP BY role

存在確認

User.exists?(1)                         # IDで確認
User.exists?(name: "田中太郎")          # 条件で確認
User.where(active: true).exists?
User.where(active: true).none?          # 0件かどうか

select・pluck

# select はActiveRecordオブジェクトを返す
User.select(:id, :name)

# pluck は値の配列を返す(軽量)
User.pluck(:name)                   # => ["田中太郎", "鈴木花子"]
User.pluck(:id, :name)              # => [[1, "田中太郎"], [2, "鈴木花子"]]

リレーション

アソシエーションの定義

class User < ApplicationRecord
  has_many :posts
  has_many :comments, through: :posts
  belongs_to :team, optional: true
  has_one :profile
end

class Post < ApplicationRecord
  belongs_to :user
  has_many :comments
end

アソシエーションの使い方

user = User.find(1)
user.posts                      # そのユーザーの投稿一覧
user.posts.count
user.posts.create(title: "新しい記事")
user.posts.where(published: true)

post = Post.find(1)
post.user                       # 投稿者
post.user.name

N+1問題と includes

# N+1が発生するコード(ユーザーごとにSQLが発行される)
User.all.each do |user|
  puts user.posts.count   # ← ここでSQLが都度発行される
end

# includes で一括取得(2回のSQLで済む)
User.includes(:posts).each do |user|
  puts user.posts.count
end

発行されるSQL(includes使用時):

SELECT * FROM "users"
SELECT * FROM "posts" WHERE "posts"."user_id" IN (1, 2, 3, ...)

joins

# INNER JOIN(関連レコードがあるユーザーだけ取得)
User.joins(:posts)
User.joins(:posts).where(posts: { published: true })

# LEFT JOIN(関連がなくても取得)
User.left_joins(:posts)

スコープ

よく使う検索条件をスコープとして定義しておくと再利用できます。

class User < ApplicationRecord
  scope :active,   -> { where(active: true) }
  scope :recent,   -> { order(created_at: :desc) }
  scope :by_role,  ->(role) { where(role: role) }
end
User.active
User.active.recent
User.by_role("admin")
User.active.by_role("admin").limit(10)

バリデーション

class User < ApplicationRecord
  validates :name,  presence: true, length: { maximum: 50 }
  validates :email, presence: true, uniqueness: true,
                    format: { with: URI::MailTo::EMAIL_REGEXP }
end

バリデーションは saveupdatecreate 時に自動で実行されます。

user = User.new(name: "")
user.valid?            # => false
user.errors[:name]     # => ["can't be blank"]
user.errors.full_messages  # => ["Name can't be blank"]

バリデーションをスキップして保存したい場合:

user.save(validate: false)

コールバック

class User < ApplicationRecord
  before_save  :normalize_email
  after_create :send_welcome_email

  private

  def normalize_email
    self.email = email.downcase.strip
  end

  def send_welcome_email
    UserMailer.welcome(self).deliver_later
  end
end

主なコールバック:

タイミング コールバック
保存前 before_validation, before_save, before_create, before_update
保存後 after_save, after_create, after_update, after_commit
削除前後 before_destroy, after_destroy

SQLを確認する

発行されるSQLはRailsコンソールで確認できます。

bin/rails console
User.where(active: true).to_sql
# => "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"active\" = 1"

User.includes(:posts).explain
# => EXPLAIN for: SELECT ...(実行計画)

開発環境ではログ(log/development.log)にも全SQLが出力されます。

DBに直接ログインして確認する方法は「SQLiteチートシート:ログインからスキーマ確認・DMLまとめ」「MySQLチートシート:ログインからスキーマ確認・DMLまとめ」「PostgreSQLチートシート:ログインからスキーマ確認・DMLまとめ」を参照してください。


まとめ

操作 メソッド
全件取得 Model.all
IDで1件 Model.find(id)
条件で1件 Model.find_by(条件)
条件で複数 Model.where(条件)
作成 Model.create(属性)
更新 record.update(属性)
削除 record.destroy
N+1対策 Model.includes(:関連名)

RailsのDBマイグレーション操作は「Rails のDB操作コマンド入門:db:create から db:migrate まで」を参照してください。

モデルのテストの書き方は「RSpec入門:インストールからモデルスペックの書き方まで」を参照してください。