Railsのscopeのソースコードを読んでいきます。
u = User.new(name: 'sample name')
scopeを読んでいくために、上記のようなオブジェクトをサンプルとして作成します。
1: class User < ApplicationRecord
2:
3: binding.pry
=> 4: scope :recent, -> { order(id: :desc).limit(5) }
5: end
中を読んでいきます。
165: # We are able to call the methods like this:
166: #
167: # Article.published.featured.latest_article
168: # Article.featured.titles
169: def scope(name, body, &block)
=> 170: unless body.respond_to?(:call)
171: raise ArgumentError, "The scope body needs to be callable."
172: end
173:
174: if dangerous_class_method?(name)
175: raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
bodyがcallを呼べなかったら、例外を返す。
今はbodyがcallを呼べるので次へ。
169: def scope(name, body, &block)
170: unless body.respond_to?(:call)
171: raise ArgumentError, "The scope body needs to be callable."
172: end
173:
=> 174: if dangerous_class_method?(name)
175: raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
176: "on the model \"#{self.name}\", but Active Record already defined " \
177: "a class method with the same name."
178: end
179:
nameがクラスメソッドとして定義されていないか判定。
今は定義されていないので次へ。
175: raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
176: "on the model \"#{self.name}\", but Active Record already defined " \
177: "a class method with the same name."
178: end
179:
=> 180: if method_defined_within?(name, Relation)
181: raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
182: "on the model \"#{self.name}\", but ActiveRecord::Relation already defined " \
183: "an instance method with the same name."
184: end
185:
nameがインスタンスメソッドとして定義されていないか判定。
今は定義されていないので次へ。
181: raise ArgumentError, "You tried to define a scope named \"#{name}\" " \
182: "on the model \"#{self.name}\", but ActiveRecord::Relation already defined " \
183: "an instance method with the same name."
184: end
185:
=> 186: valid_scope_name?(name)
187: extension = Module.new(&block) if block
188:
189: if body.respond_to?(:to_proc)
190: singleton_class.define_method(name) do |*args|
191: scope = all._exec_scope(name, *args, &body)
scopeの名前として有効かどうか判定する。nameがメソッドとして定義されていないので、次へ。
182: "on the model \"#{self.name}\", but ActiveRecord::Relation already defined " \
183: "an instance method with the same name."
184: end
185:
186: valid_scope_name?(name)
=> 187: extension = Module.new(&block) if block
188:
189: if body.respond_to?(:to_proc)
190: singleton_class.define_method(name) do |*args|
191: scope = all._exec_scope(name, *args, &body)
192: scope = scope.extending(extension) if extension
blockが存在しているなら、blockを引数としたてModuleを新しく作る。今回はblockが存在しないので、次へ。
184: end
185:
186: valid_scope_name?(name)
187: extension = Module.new(&block) if block
188:
=> 189: if body.respond_to?(:to_proc)
190: singleton_class.define_method(name) do |*args|
191: scope = all._exec_scope(name, *args, &body)
192: scope = scope.extending(extension) if extension
193: scope
194: end
bodyがto_procメソッドをを呼べるか判定。呼べるので、if分の中へ。
185:
186: valid_scope_name?(name)
187: extension = Module.new(&block) if block
188:
189: if body.respond_to?(:to_proc)
=> 190: singleton_class.define_method(name) do |*args|
191: scope = all._exec_scope(name, *args, &body)
192: scope = scope.extending(extension) if extension
193: scope
194: end
195: else
bodyで与えられた処理を実装する、nameというクラスメソッドを定義する。
198: scope = scope.extending(extension) if extension
199: scope
200: end
201: end
202:
=> 203: generate_relation_method(name)
204: end