私は次の動作に気づきました(そして黒点コードで確認しました)
class Foo < ActiveRecord::Base
def bar
search_str = "foo"
Boo.search do
keywords(search_str)
p self.id
p self
end
end
end
上記のコードでは、DSLブロックはコンテキストで定義された変数にアクセスできます。ただし、内部ブロックは、 (クラスのインスタンスではなく )クラスself
のインスタンスを指し
ます。オブジェクトのを取得する代わりに、にアクセスしようとすると、オブジェクトのを取得します。Sunspot::DSL::Search
Foo
self.id
id
Foo
id
Sunspot::DSL::Search
サンポットはメソッドでバインディングスワッピング/委任の魔法を使っていると思います Util.instance_eval_or_call
。
Sunspotがこれを行う理由と、ドキュメントにこの動作に関する警告がない理由に興味があります。
編集:
黒点の検索方法は、このリンクにあります
以下のコードは私のポイントを示しています。このメソッドfoo
には、期待どおりに動作するブロックがあります。メソッドbar
では、ブロックは動作しません。
class Order < ActiveRecord::Base
def foo
p self.class.name # prints Order
# The `self` inside the block passed to the each method
# points to an object of type Order (as expected)
# This is the normal block behavior.
[1,2,3].each do |val|
p self.class.name # prints Order
end
end
def bar
p self.class.name # prints Order
# the `self` inside the block passed to the search method
# points to an object of type Sunspot::DSL::Search.
# This is NOT the normal block behavior.
Order.search do
keywords("hello")
p self.class.name # prints Sunspot::DSL::Search
end
end
注2
通常のブロック動作を変更するコードをSunspotソースツリーに配置しました。私の質問は、このようにバインディングをリギングする理由についてです。
注3
具体的にはid
、ブロック側でメソッドを呼び出しているときに問題が見つかりました。メソッドは、ブロック内のsearch
メソッド呼び出しをDSLオブジェクトに委任し、メソッドが見つからない場合、呼び出しは呼び出し元のコンテキストに再委任されます。Searchメソッドは、委任コードを登録する前に、DSLオブジェクトから必須メソッドを除くすべてを取り除きます。id
メソッドは削除されません。これが問題の原因です。他のすべての方法では、委任は正常に機能します。
この動作は、Sunspotメソッドのドキュメントには記載されていません。