[Rails]scopeについて:ActiveRecord::Relationオブジェクト・クエリインターフェース
モデルにメソッドを定義する場合、以下2つが挙げられる。
- スコープで定義する場合
- クラスメソッドで定義する場合
これらの違いについて、詳しく説明していきます。
スコープとクラスメソッド違いの大枠
scopeについて書いていく前に、違いについて先にまとめます。
スコープ | クラスメソッド | |
---|---|---|
定義方法 | scopeメソッドを使用 | クラスメソッドを定義 |
目的 |
同じようなクエリを共通化する クエリメソッドの作成 |
モデル全体で共通のメソッドを定義する クラスメソッドの作成 |
呼び出し方 | モデル名.スコープ名 | モデル名.クラスメソッド名 |
返り値 | ActiveRecord::Relationオブジェクト | レコードの配列 |
使用時の引数 | 引数をとることができる | 引数をとることができる |
チェーンメソッド | チェーンメソッドとして使用可能 | チェーンメソッドとして使用可能 |
大きく、違いは返り値の型と使用方法にある。
[返り値の型]
- スコープはActiveRecord::Relationオブジェクトを返し、チェーンメソッドとして使用することができる。
- クラスメソッドはレコードの配列を返し、チェーンメソッドとして使用することはできない。
[使用方法]
- スコープはモデル名.スコープ名という形式で呼び出すことができ、
- クラスメソッドはモデル名.クラスメソッド名という形式で呼び出す。
"動的にクエリを生成する"とは...
動的にクエリを生成するとは、
実行時に引数に応じてクエリの内容を変更したり、条件を追加したりすることを指す。
ex. スコープを使用して、以下のようなクエリを定義することができます。
scope :by_name, -> (name) { where(name: name) if name.present? }
このスコープでは、引数で渡されたnameが存在する場合には、nameに一致するレコードを取得するクエリが生成される。引数でnameが渡されなかった場合には、条件式は生成されない。
= このように、
引数によってクエリの条件を変更したり、動的にクエリを生成することができるのがスコープの特徴。
一方、クラスメソッドでは、実行時に引数に応じてクエリを動的に変更することはできない。
固定的なクエリを定義する場合に使用する。
- スコープに引数を渡す機能は、クラスメソッドによって提供される機能を単に複製したもので
スコープに引数が渡される場合はクラスメソッドの使用が推奨。
scope
- スコープは、ActiveRecordによって提供されるメソッドであり、
モデルのクラスに対してクエリメソッドを定義できる。
クエリメソッド:
ActiveRecordにおいて、データベースからデータを取得するためのメソッドのこと。
クエリメソッドを使うことで、データベースに対してSELECT、INSERT、UPDATE、DELETEなどの
SQL文を発行することができる。
- スコープを定義することで、同じ条件を複数の場所で使いまわしたり、
複数の条件を組み合わせたクエリを簡単に実装することができる。
以下では、上記で説明したscopeの特徴のActiveRecord::Relationオブジェクトと、
そことも関係するActive Recordのクエリインターフェースについてまとめていきます。
ActiveRecord::Relationオブジェクト
①. ActiveRecord::Relationオブジェクトは、
Active Recordでデータベースから取得したデータを表現するオブジェクト。
例えば、以下のようにUserモデルからデータを取得した場合、
usersというActiveRecord::Relationオブジェクトが返されます。
users = User.where(age: 20)
②. Active Recordのクエリインターフェースを提供する。
例えば、以下のようにwhereメソッドを使用して条件を指定することができる。
users = User.where(age: 20)
users = users.where(name: 'John')
また今までのブログでも使用してきたように、orderメソッドを使用してソート順を指定することもできる。
users = User.order(:name)
③. 遅延評価を行う。
whereやorderなどのメソッドは、実際にSQLクエリを生成するわけではなく代わりに、
クエリを実行するまで遅延させ、必要なタイミングでクエリを発行することで、効率的にデータベースアクセスを
行うことができるようになっている。
ex. 以下のようにUserモデルからデータを取得した場合、SQLクエリはまだ発行されておらず、
whereメソッドとorderメソッドの条件が組み合わされたSQLクエリが発行されるタイミングで実行される。
users = User.where(age: 20)
users = users.order(:name)
Active Recordのクエリインターフェースとは
-
Active Recordが提供するデータベースとのやり取りに用いるAPIのこと。
使用することで、Rubyのコードからデータベースに対して様々な操作を行うことができる。
1. クエリインターフェースは、
Active Recordのメソッドチェーン形式のクエリビルダーを通じて利用することができる。
メソッドチェーン形式のクエリビルダーでは、複数のクエリメソッドをつなぎ合わせることで、
複雑なクエリを簡潔に表現することができる。
# ex. タイトルが"Rails"であるか、内容に"Ruby"を含む記事を取得する
Post.where("title = ? OR body LIKE ?", "Rails", "%Ruby%")
2. クエリインターフェースには、
データの取得や更新、削除、集計など、様々な操作を行うためのメソッドが提供されている。
例えば、whereメソッドを使用することで、特定の条件を満たすレコードのみを取得することができる。
また、orderメソッドを使用することで、レコードの並び順を指定することができます。
以下、メソッドのまとめです。
Active Recordのクエリインターフェースで提供されている代表的なメソッド一覧
メソッド名 | 機能 | 使用型 |
---|---|---|
select | 取得する列を指定する | SELECT |
distinct | 重複したレコードを除外する | SELECT |
where | 条件を指定する | WHERE |
or | OR条件を追加する | WHERE |
not | NOT条件を追加する | WHERE |
order | ソート順を指定する | ORDER BY |
reorder | ソート順を上書きする | ORDER BY |
group | グループ化するカラムを指定する | GROUP BY |
having | グループ化した結果に対する条件を指定する | HAVING |
limit | 取得する最大行数を指定する | LIMIT |
offset | 取得する開始位置を指定する | OFFSET |
joins | テーブルを結合する | JOIN |
left_outer_joins | 左外部結合を行う | LEFT OUTER JOIN |
includes | 関連テーブルを一括で取得する | - |
preload | 関連テーブルを先読みする | - |
eager_load | 関連テーブルを即座に取得する | - |
references | クエリに含まれるテーブル名を指定する | - |
merge | 別のActive Recordのリレーションをマージする | - |
count | 指定した条件に一致するレコード数を取得する | SELECT COUNT(*) |
sum | 指定したカラムの合計を取得する | SELECT SUM(column) |
average | 指定したカラムの平均を取得する | SELECT AVG(column) |
minimum | 指定したカラムの最小値を取得する | SELECT MIN(column) |
maximum | 指定したカラムの最大値を取得する | SELECT MAX(column) |
クエリインターフェースは、SQL文を直接書くことなく、Rubyのコードだけでデータベース操作を行えるため、
開発効率の向上やコードの可読性の向上につながります。
Discussion