【続・find と where の違い 】ActiveRecord::Relation を学ぶ。

こんにちは。7cocoです。
先日 Qiita に書いた [ActiveRecord の find と where の違い。](http://qiita.com/7coco/items/b08c842aece4b7f28f55) でのコメントを受け、 ActiveRecord::Relation について調べてみました。

自分用のメモになります。

# ActiveRecordとは
- データベースにクエリを発行する。
- 様々なデータベースとの互換性がある。
- データベースの種類にかかわらず同じ表記を使用できる。

## データベースからオブジェクトを取り出す検索メソッド
- [create_with](http://railsdoc.com/references/create_with)
- [distinct ( 英語のページ )](http://apidock.com/rails/ActiveRecord/QueryMethods/distinct)
- [eager_load](http://railsdoc.com/references/eager_load)
- [extending](http://railsdoc.com/references/extending)
- [from](railsdoc.com/references/from)
- [group](http://railsdoc.com/references/group)
- [having](http://railsdoc.com/references/having)
- [includes](http://railsdoc.com/references/includes)
- [joins](railsdoc.com/references/joins)
- [limit](http://railsdoc.com/references/limit)
- [lock](http://apidock.com/rails/ActiveRecord/QueryMethods/lock)
- [none](http://apidock.com/rails/ActiveRecord/QueryMethods/lock)
- [offset](http://railsdoc.com/references/offset)
- [order](http://railsdoc.com/references/order)
- [preload](http://apidock.com/rails/ActiveRecord/QueryMethods/preload)
- [readonly](http://railsdoc.com/references/readonly)
- [references](http://railsdoc.com/references/references)
- [reorder](http://railsdoc.com/references/reorder)
- [reverse_order](http://railsdoc.com/references/reverse_order)
- [select](http://railsdoc.com/references/select)
- [uniq](http://railsdoc.com/references/uniq)
- [where](railsdoc.com/references/where)
- bind いいページが見つからない……。

上のメソッドは全て ActiveRecord::Relation のインスタンスを返します。
つまり今回注目するのはこのメソッドたちが返すものです。

## 単一のオブジェクトを取り出す

- [find](http://railsdoc.com/references/find)
- [take](http://railsdoc.com/references/take)
- [first](http://railsdoc.com/references/first)
- [last](http://railsdoc.com/references/last)
- [find_by](http://railsdoc.com/references/find_by)

上記メソッドは単一オブジェクトを返します。

## 複数のオブジェクトをバッチで取り出す
- [find_each](http://railsdoc.com/references/find_each)
- [find_in_batches](http://railsdoc.com/references/find_in_batches)

上記は一度にメモリに読み込めないような大量のレコードに対するバッチ処理のためのメソッドです。

# ActiveRecord::Relation
上で紹介したメソッドたちが返すもの。下記のようなメソッドがあります。

- [==](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-3D-3D)
    - レシーバと引数を == で比べる。
- [any?](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-any-3F)
    - レコードがあるかどうかを boolean で返す。
- [blank?](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-blank-3F)
    - レコードが空であるかどうかを返す。
- [build](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-build)
    - `new` メソッドのエイリアス
- [cache_key](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-cache_key)
    - クエリによってフェッチされたことのあるキャッシュキーを返す。キャッシュキーはマッチしたレコードの数と最終更新時刻とともにビルドされる。クエリにマッチするレコードや存在するレコードが更新または削除された時、キャッシュキーも変わる。
- [create](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-create)
    - 新しいレコードを作ろうとする。バリデーションに失敗するとイニシャライズオブジェクトを返す。 ActiveRecord::Base.create と同じ引数をとる。
- [create!](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-create-21)
    - `create`に似ているが、バリデーションエラーが起こった場合例外を吐く。
- [delete](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-delete)
    - SQLの `DElETE` ステートメントを用いて引数とマッチするプライマリーキーの行を削除する。そして削除した行の数を返す。配列を用いることで複数行の削除が可能。
- [delete_all](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-delete_all)
    - 最初にレコードをインスタンス化することなくレコードの削除を行う。そのため、 `destroy` メソッドの呼び出しやコールバックの呼び出しは行われない。
- [destroy](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-destroy)
    - `id` を渡されたオブジェクトを削除する。オブジェクトは初めにインスタント化される。
- [destroy_all](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-destroy_all)
    - それぞれのレコードのインスタンス化とその `destroy` メソッドの呼び出しを行ってレコードを削除する。
- [eager_loading](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-eager_loading-3F)
    - リレーションに eager loading が必要かどうかを返す。
- [empty?](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-empty-3F)
    - レコードがないかどうかを返す。
- [encode_with](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-encode_with)
   - リレーションオブジェクトArrayをシリアル化する。
- [explain](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-explain)
    - リレーションによって呼び出されるクエリーに `EXPLAIN` を走らせ、結果を文字列で返す。
- [find_or_create_by](api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-find_or_create_by)
    - 与えられた属性からレコードを見つける。見つからなかった場合はその属性のレコードを作成する。
- [find_or_create_by!](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-find_or_create_by-21)
    - `find_or_create_by` と大体同じだが、作られたレコードが invalid だった場合に例外を吐く。
- [find_or_initialize_by](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-find_or_initialize_by)
    - `find_or_create_by` と似ているが、 `create` の代わりに `new` を呼ぶ。
- [joined_includes_values](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-joined_includes_values)
    - プリロードのためのマークされているジョインを行う。eager load を行う必要がある。
- [load](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-load)
    - まだロードされていない場合、データベースからレコードをロードする。
- [many?](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-many-3F)
    - レコードの数が1よりも大きいかどうかを返す。
- [new](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-new)
    - 現在のスコープを維持しながら relation から 新しいレコードを作る。
- [none?](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-none-3F)
    - レコードがないかどうかを返す。
- [one?](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-one-3F)
    - レコードがちょうど一つかどうかを返す。
- [reload](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-reload)
    - リレーションのリロードを強制的に行う。
- [scoping](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-scoping)
    - 現在のスコープのすべてのクエリをスコープする。
- [size](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-size)
    - レコードのサイズを返す。
- [to_a](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-to_a)
    - relation object を Array にする。
- [to_sql](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-to_sql)
    - relation の SQL statement を返す。
- [uniq_value](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-uniq_value)
    - `uniq`メソッドと`uniq!`メソッドは非推奨。 `uniq_value`は後方互換性を維持するために`distinct_value`に委譲する。代わりに`distinct_value`を使用すること。
- [update](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-update)
    - オブジェクトを更新してバリデーションを通過したらデータベースに保存する。
- [update_all](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-update_all)
    - 与えられた情報に現在の relation をのすべてのレコードを更新する。
- [where_value_hash](http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-where_values_hash)
    - where条件のハッシュを返す。

正直な感想としては「わー、なんかいっぱいあるんだなあ。」みたいな感じですが、 `find_or_create_by` あたりは使いどころも多い便利メソッドなので積極的に使っていきたいです。

## まとめ
- ActiveRecord::Relation は検索クエリを組み立てるもので、検索結果のオブジェクトとは異なるもの。
- 上記メソッドをチェインすることでクエリを走らせる回数を減らしつつ柔軟なデータの取得や操作が可能。
- 使いこなすにはまだまだ経験と勉強不足。

## 参考文献
- [いいねと思った Rails メソッド 10](http://qiita.com/pekepek/items/c57d4859e6e1ec8b1ad1)
- [Active Record クエリインターフェイス](railsguides.jp/active_record_querying.html)
- [Active Record Relation](api.rubyonrails.org/classes/ActiveRecord/Relation.html)