質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

Q&A

解決済

1回答

3422閲覧

ActiveRecordではwhereが実行された際にはどうやってrelation/query_methodsのwhereが呼ばれるのでしょうか?

coffee_man

総合スコア13

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

0グッド

1クリップ

投稿2017/04/27 09:58

###ActiveRecordのwhereの仕組み

ActiveRecordのwhereの仕組みに関して教えてください。ActiveRecordのソースを読み込みpryで動作を止めてひとつひとつ確認しています。

User.where(id: 1)

を実行するとrails/activerecord/lib/active_record/querying.rbのdelegateでwhereがto: allになっています。

delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :left_joins, :left_outer_joins, :or, :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :distinct, :references, :none, :unscope, :merge, to: :all

したがってrails/activerecord/lib/active_record/scoping/named.rb
のallに処理が渡されています。

def all if current_scope current_scope.clone else default_scoped end end

ここのdefault_scopeの処理のあと
rails/activerecord/lib/active_record/relation/query_methods.rb
のwhereに処理が行きます。

def where(opts = :chain, *rest) if :chain == opts WhereChain.new(spawn) elsif opts.blank? self else spawn.where!(opts, *rest) end end

これはどのようにして実現しているのでしょうか?つまりどうやってdefault_scopeの処理の後にrelation/query_methods.rbのwhereへ行くようにしているのでしょうか?

最終的にはこちらの記事のThe Beauty of ActiveRecord::RelationにあるようにActiveRecord::Relationを使ったメソッドの数珠つなぎのような物を実装したいと考えております。

ただその前にActiveRecordのwhereが呼ばれた際にwhere->all->where(relation/query_methods)とつなげている仕組みを理解しなければ実現できそうにありません。

ソースのここを読めば分かるかも、といったヒントでも構いませんので教えていただけますでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

coffee_manということはjava使い様でしょうか、javaでrubyという黒魔術を
説明するのは難しいのですが。
delegateは、委譲ですmethodを引数に渡せないjavaで説明するのは難しいので
delegateされているmethodを実行する前にallが実行されるぐらいのイメージでいてください

つまりどうやってdefault_scopeの処理の後にrelation/query_methods.rbのwhereへ行くようにしているのでしょうか?
ではなく、relation/query_methods.rbのwhereへ行く前にdefault_scopeを実行するようにあらかじめ義務付けられているのです。

で、そのあとの処理も書いておきますが
current_scope
ですが、すでに、これにはwhere(id: 1)が入っておりますので
current_scopeにはActiveRecord::Relationを返し
実行されるのはcurrent_scope.cloneです。
で、rubyにおいては、method内で最後に評価された式が戻り値になりますので
current_scope.cloneが戻り値になります。
で、このcloneが曲者で、元のcurrent_scopeと別インスタンスなのですが
attributeは共有しているという…。
※これで、任意のタイミングまでmethodchainしたクエリが自由に発行できるわけですが…
で、各methodでWhereChainなどにストックしていって、最後にarelというライブラリを使って
SQLに変更するのがactive_recordの大まかな流れです。

投稿2017/04/28 02:48

moke

総合スコア2241

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coffee_man

2017/04/28 08:47

mokeさん、ご回答ありがとうございます。ここ数時間、ずっとmokeさんの回答を何度も読んでおります。 なんとなく「relation/query_methods.rbのwhereへ行く前にdefault_scopeを実行するようにあらかじめ義務付けられている」のあたりの理解が不足していたことが分かりました。 こちらの[ドキュメント](http://api.rubyonrails.org/classes/Module.html#method-i-delegate)ではFoo.new.helloがGreeterのhelloに委譲されているだけのように見えます。 仮にFooにhelloメソッドが存在した場合、これをmokeさんのおっしゃるようにFooのhelloへ行く前にGreater内にある処理を実行するように義務付けるにするはどのように書けばいいのでしょうか? ActiveRecordで「***へ行く前に***の実行を義務つけ」というのがdelegateで行われているという理解ですが、ここがそもそも間違っているのでしょうか?なんとなくdelegateのような気がするだけで本当の理解にはいたっておりません。
moke

2017/04/28 09:39 編集

もちろん、それが、一般的なdelegateなのですが、この場合の allはclassでもなんでもなくただの、methodです、コードを読むとわかるのですが railsのdelegateはtoの先と合わせた新たなmethodを作ってmodule_evalしてるだけなんですよ。 引数にmethodを取れ、さらにmethodを定義して実行できるというrubyの静的言語からは 考えつかないような特殊性が垣間見れます。 でもこれによって、Rails3までの不便さがなくなっているのでありがたい限りなのですが。 まあ、気持ち悪いと思う人がいてもおかしくないと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問