📖

[Rails]scopeについて:ActiveRecord::Relationオブジェクト・クエリインターフェース

2023/04/15に公開

モデルにメソッドを定義する場合、以下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のクエリインターフェース

  • 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