#ActiveRecord::Relation
##はじめに
最後ですね。25日目に何を書こうか悩みましたが、このカレンダー全体を通してActiveRecordを主体として書いてきたつもりですので、最後も結局ActiveRecord関連です。また初心者が中級者になる段階として、ソースを見る
という段階があると思います。最後はそんな、メソッドのソースを見るということをやってみます。
環境
Rails 5.1.6
ruby 2.3.1
##ActiveRecord::Relation
まず最初にActiveRecord::Relation
とはいわゆるO/Rマッパーというやつです。簡単に説明すると、オブジェクティブ指向プログラミング言語と、 データベース間を繋ぐ役割を果たしています。クエリを発行したり、そのクエリをプログラム内で再利用可能にしたり、データベースから取得したデータをプログラム内で扱えるように変換したりしています。今回はソースと共にActiveRecord::Relationのメソッドの内容を見ていきます。
##find_or_initialize_by
ではメソッドたちを見てみましょう。まずはfind_or_initialize_by
こいつは確かomniauth
を使うときに出てきた奴。
def find_or_initialize_by(attributes, &block)
find_by(attributes) || new(attributes, &block)
end
find_by
してあったらそのまま返し、なかったらnew
してくれる奴。sns認証の時に用いられたりします。
##first_or_create
def first_or_create(attributes = nil, &block) # :nodoc:
first || create(attributes, &block)
end
最初見たとき、こんなもんUser.first_or_create
とかやったら絶対最初のレコードが帰ってくるやんって思ってました。違います。whereと併用して使います。
User.where(name: 'taro').first_or_create(age: 18)
whereで条件を指定し、名前がtaroという人がいなければ歳を18としてレコードを作成します。
同じ情報を持ったレコードを作らせたくない時に使います。
##find_or_create_by
first_or_createに似た奴がこちら、ていうかほぼ同じ。こっちの方がメソッドチェーンしなくて済むので好き。
def find_or_create_by(attributes, &block)
find_by(attributes) || create(attributes, &block)
end
##find_each
以前アンチパターンで紹介したこやつ。eachによって数千、数万のレコードに対する同じ処理を一気にやるのではなく分割してくれる奴。whereとチェーンして使える。batch_sizeに1000が指定されてますね。ここで分割数を設定しているのでしょう。
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil)
if block_given?
find_in_batches(start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do |records|
records.each { |record| yield record }
end
else
enum_for(:find_each, start: start, finish: finish, batch_size: batch_size, error_on_ignore: error_on_ignore) do
relation = self
apply_limits(relation, start, finish).size
end
end
end
下記のように使えば21歳以上のユーザーを1000件づつ処理してくれる。
Person.where("age > 21").find_each do |person|
person.party_all_night!
end
まだまだありますが、メソッドのソースはこんな感じでした。今回はメソッドの紹介風にソースを眺めてみましたが、実際としては、書いたプログラムがうまく機能しなかったり、メソッドの帰り値が予想と違うだとか、そうゆう時にメソッドの中身を見て、原因を探っていく時に見るものです。
他の記事を書いた時も何回かサンプルコードがうまく動作しないとなってはソースを見て、の繰り返しでした。
ソースコードの読解力は中級者になるには必須の力でしょう。
##まとめ
今回はActiveRecord::Relationはなんぞやってとこと、そのメソッドたちをソースコードと共に紹介しました。
が、一番伝えたかったのはソースコードを見よう!ということです。
実は最初書こうと思ってた記事はUser.new
のnew
をソースコードを見ながら紐解いてみようという記事を書くつもりでした。ですが、しっかり説明しようとするとかなりボリューミーになりそうだと途中で気づき、というかそもそも伝えるべきはnew
じゃなくてソースコードを読むべしってことなんじゃねってなってこんな記事になりました。(一応テーマも初心者→中級者ですし)
##最後に(エモエモ)
この25日間、とても大変だったです、ええ。最初の数日は記事の溜め込みがあったので良かったのですが、ストックが尽きた途端、時間に終われる日々が始まりました。仕事終わりにコワーキングスペースに駆け込み20時から3時間ほどで、調べ、サンプルコードを書き、記事にまとめる。ご存知の通りいつもギリギリでした。また、調べの段階で詰まった時は取り急ぎの記事を書いてたりしました。(すみません...ていうかほぼ今回にも当てはまる...)
でもまあ得たものは大きいです。取り急ぎだろうが何だろうが毎日知識をinputしoutputする。そうすると自分に必要な知識も見えてきます。
後何より見てくれている人がいると、モチベにもなるし間違った情報は書けないと必死になりますね。ほんと見てくれた方には感謝します。
また来年も頑張ろうかなと思ってたりする。次は濃厚な記事を毎日書けるよう頑張ります!!
##参考にしたの
ActiveRecord::Relationとは一体なんなのか
https://doruby.jp/users/whale/entries/ActiveRecord--Relation%E3%81%A8%E3%81%AF%E4%B8%80%E4%BD%93%E3%81%AA%E3%82%93%E3%81%AA%E3%81%AE%E3%81%8B
覚えておくと幸せになれるActiveRecord::Relationメソッド6選
https://qiita.com/Yama-to/items/4696e9d43ebec6012129
What is the difference between Class and Klass in ruby?
https://stackoverflow.com/questions/4299289/what-is-the-difference-between-class-and-klass-in-ruby
Rubyでメソッドの定義場所を見つける方法
https://qiita.com/jnchito/items/fc8a61b421d026a23ffe