1年くらい前にRubyの勉強のためにActiveRecordクエリインタフェースでよく利用するメソッドをまとめたもの
参考
・https://railsguides.jp/active_record_querying.html
オブジェクトの取り出し
単一のオブジェクトを取り出す
find
主キーに対するオブジェクトを返す
find_by
キーを指定して対するオブジェクトを返す
first
主キー順の最初のレコードを取り出す
last
主キー順の最後のレコードを取り出す
複数のオブジェクトをバッチで取り出す
find_each
分割してレコードを取得して処理をする。
デフォルトでは1000件づつ取得する。
各レコードを1つのモデルとして個別にブロックにyieldする。
主なオプション
・batch_size:1回のバッチで取り出すレコード数を指定できる。
・begin_at:ある主キーのIDより小さいIDを除外したい場合に指定できる。バッチ処理の開始位置を指定。
・end_at:ある主キーのIDより大きいIDを除外したい場合に指定できる。バッチ処理の終了位置を指定。
find_each_batches
find_eachとほぼ同じ。違いは各レコードを個別にではなくモデルの配列としてブロックにyieldする。
条件
where
条件を指定して条件に当てはまるレコードをすべて取得する。
文字列、配列、Hash、nilで指定できる。ハッシュで指定することが多い。
# Hashで指定
Book.where(category_id: 1)
# SQL
# SELECT books.* FROM books WHERE books.category_id = 1
# to_sqlメソッドを使うとSQLを表示できて便利
# Book.where(category_id: 1).to_sql
# 文字列指定
Book.where("category_id = '1'")
# 配列指定
Book.where("category_id = ?", params[: category_id])
範囲指定
rangeを渡すとBetween文で範囲指定してくれるので便利
Book.where(created_at: Time.now.in_time_zone.all_month)
# SQL
SELECT books.* FROM books WHERE books.created_at BETWEEN '2016-06-01 00:00:00' AND '2016-06-30 23:59:59' )
NOT条件
SQLのNOTクエリはwhere.notで表せる
並び替え
orderメソッドを使用する
Book.order(created_at: :desc)
Book.order(created_at: :asc)
特定のフィールドだけ取り出す
select
特定のフィールドだけを取り出す
Book.select(:name).distinct
# distinct:重複排除
グループ
group
GROUP BY句を追加する
Book.select(:category_id).group(:category_id)
Having
having
HAVING句を追加する
Book.select(:category_id).group(:category_id).having("count(category_id) > ?", 100).count()
条件を上書きする
unscope
特定の条件を取り除く
# unscopeなし
Book.select(:id).where('id > 400').order('id asc').to_sql
# => "SELECT `books`.`id` FROM `concerts` WHERE (id > 400) ORDER BY id asc"
# unscopeあり
Book.select(:id).where('id > 400').order('id asc').unscope(:where, :order, :select).to_sql
# => "SELECT `books`.* FROM `concerts`"
only
条件を上書きする(指定したクエリのみ使用する)
# onlyなし
Book.select(:id).where('id > 400').order('id asc').to_sql
# => "SELECT `books`.`id` FROM `concerts` WHERE (id > 400) ORDER BY id asc"
# onlyあり
Book.select(:id).where('id > 400').order('id asc').only(:where, :select).to_sql
# => "SELECT `books`.`id` FROM `concerts` WHERE (id > 400)
reorder
デフォルトのスコープの並び順を上書きする
# デフォルトで並び順を設定していたとする
class Book < ApplicationRecord
default_scope-> {order(:created_at)}
end
# 新しい順で欲しくなったんだけど… (他に名前順で…)
Book.order('created_at DESC')
# => ORDER BY created_at ASC, created_at DESC
Book.order(:name)
# => ORDER BY created_at ASC, name ASC
# reorderを使えば
Book.reorder('created_at DESC')
# => ORDER BY created_at DESC
reverse_order
並び順が指定されている場合に並び順を逆にする
rewhere
既存のwhere条件を上書きする
Nullリレーション
none
空のリレーションを返す。レコードは返さない。
メソッドまたはスコープへの連鎖可能な応答が必要だけど結果を返したくない場合に便利
読み取り専用オブジェクト
readonly
返されたどのオブジェクトに対しても変更を明示的に禁止する
テーブルのロック
レコードを更新できないようロックする
楽観的ロック(optimatic)
複数のユーザーが同じレコードを編集することを許す。
テーブルにlock_versionという名前のinteger型カラムが必要。
悲観的ロック(pessimistic)
データベースが提供するロック機構を使用する。
テーブル結合
join
テーブルを関連付ける。(INNER JOIN)
# ネストした関連付け(単一)
Book.joins(comments: :guest)
# ネストした関連付け(複数)
Book.joins({ comments: :guest }, :tags)
関連付けを一括読み込みする
N+1問題を解決するためeager loadingを行う。
includes,eager_load, preloadメソッドがある。
基本的にはincludesで良いが必ずJOINしたい場合はeager_load、JOINしたくない場合はpreloadを使う。
こちらのqiita記事がオススメ
http://qiita.com/k0kubun/items/80c5a5494f53bb88dc58
スコープ
関連オブジェクトやモデルへのメソッド呼び出しとして参照される、よく使用されるクエリを指定することができる。
class Book < ApplicationRecord
scope :publishe, -> { where(:published: true) }
end
# 引数あり
class Book < ApplicationRecord
scope :created_before, ->(time) { where("created_at < ?", time) }
end
メソッドチェイン
メソッドを連続的に呼び出すこと
新しいオブジェクトを検索またはビルドする
find_or_create_by
指定された属性を持つレコードが存在するかどうかをチェックし存在しなければcreateする。
新しいレコードの作成時'locked'属性をfalseに設定したいが、それをクエリに含めたくない場合
# create_withを使うパターン
Book.create_with(locked: false).find_or_create_by(name: 'Effective Ruby')
# ブロックを使うパターン
Book.find_or_create_by(name: 'Effective Ruby') do |c|
c.locked = false
end
find_or_create_by!
新しいレコードが無効な場合に例外を発生させることが可能
find_or_initialize_by
find_or_create_byと同様に動作するがcreateではなくnewを呼ぶ
SQLで検索
find_by_sql
独自のSQLを使用してレコードを検索できる。配列が返ってくる。
select_all
独自のSQLを使用してレコードを検索できる。Hashの配列が返ってくる。
pluck
テーブルから指定したカラムを取得する
ids
主キーを利用するリレーションのIDをすべて取得する
オブジェクトの存在チェック
exists?
オブジェクトが存在するかを確認する。
発行するクエリはfindと同様
計算
count, average, max, min, sumのメソッドがある。
Explain
explain を用いる
EXPLAIN
https://dev.mysql.com/doc/refman/5.6/ja/explain-output.html
http://nippondanji.blogspot.jp/2009/03/mysqlexplain.html
http://qiita.com/mucho0623/items/fa575002bf0ade699e2f