1. kamohicokamo

    Posted

    kamohicokamo
Changes in title
+ActiveRecord::Relationのソースを見てみる。 初心者→中級者へのSTEP25/25
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,105 @@
+#ActiveRecord::Relation
+##はじめに
+最後ですね。25日目に何を書こうか悩みましたが、このカレンダー全体を通してActiveRecordを主体として書いてきたつもりですので、最後も結局ActiveRecord関連です。また初心者が中級者になる段階として、`ソースを見る`という段階があると思います。最後はそんな、メソッドのソースを見るということをやってみます。
+
+**環境**
+`Rails 5.1.6`
+`ruby 2.3.1`
+
+##ActiveRecord::Relation
+まず最初に`ActiveRecord::Relation`とはいわゆる**O/Rマッパー**というやつです。簡単に説明すると、オブジェクティブ指向プログラミング言語と、 データベース間を繋ぐ役割を果たしています。クエリを発行したり、そのクエリをプログラム内で再利用可能にしたり、データベースから取得したデータをプログラム内で扱えるように変換したりしています。今回はソースと共にActiveRecord::Relationのメソッドの内容を見ていきます。
+
+ソースはこちら
+https://github.com/rails/rails/blob/66da5ea1286c2a3b428a18546f7f076722218bd4/activerecord/lib/active_record/relation.rb
+
+##find_or_initialize_by
+ではメソッドたちを見てみましょう。まずは`find_or_initialize_by`こいつは確か`omniauth`を使うときに出てきた奴。
+
+```rb
+def find_or_initialize_by(attributes, &block)
+ find_by(attributes) || new(attributes, &block)
+end
+```
+`find_by`してあったらそのまま返し、なかったら`new`してくれる奴。sns認証の時に用いられたりします。
+
+##first_or_create
+
+```rb
+def first_or_create(attributes = nil, &block) # :nodoc:
+ first || create(attributes, &block)
+end
+```
+最初見たとき、こんなもん`User.first_or_create`とかやったら絶対最初のレコードが帰ってくるやんって思ってました。違います。whereと併用して使います。
+
+```rb
+User.where(name: 'taro').first_or_create(age: 18)
+```
+whereで条件を指定し、名前がtaroという人がいなければ歳を18としてレコードを作成します。
+同じ情報を持ったレコードを作らせたくない時に使います。
+
+##find_or_create_by
+first_or_createに似た奴がこちら、ていうかほぼ同じ。こっちの方がメソッドチェーンしなくて済むので好き。
+
+```rb
+def find_or_create_by(attributes, &block)
+ find_by(attributes) || create(attributes, &block)
+end
+```
+
+##find_each
+以前アンチパターンで紹介したこやつ。eachによって数千、数万のレコードに対する同じ処理を一気にやるのではなく分割してくれる奴。whereとチェーンして使える。batch_sizeに1000が指定されてますね。ここで分割数を設定しているのでしょう。
+
+```rb
+ 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件づつ処理してくれる。
+
+```rb
+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