我正在使用active_admin,这会将meta_search引入我的项目。 (我不想用于其他任何事情)。
似乎是在我的所有模型上定义搜索方法,这意味着当我包含轮胎时,我无法使用它的搜索方法。
它如何定义方法似乎有些奇怪 - method_defined?说没有定义搜索方法,但是当我调用它时,我得到了meta_search。即使我在类中定义自己的搜索方法,当我调用Document.search时,我仍然会得到meta_search。
编辑:我对处理这类事情的一般方法感兴趣 - 我通过使用Model.tire.search解决了这个特殊问题(因为轮胎也可以通过这种方式访问),但我仍然讨厌gem我甚至没有使用可以迫使我在我的项目的其余部分使用解决方法。编辑:我不知道在答案的答案中包含代码块的好方法,所以我会把它放在这里。
# Meta_search loaded, tire is not
1.9.3p125 :001 > require "tire" #=> true
1.9.3p125 :002 > Document.send(:include, Tire::Model::Search)
=> Document(...)
1.9.3p125 :003 > Document.search
Document Load (2.1ms) SELECT "documents".* FROM "documents"
# I get meta_search, as I should
# Tire loaded (and the include Tire::Model::Search is inside the class definition), meta_search is not loaded
1.9.3p125 :001 > Document.search
# I get tire, as I should
1.9.3p125 :002 > require "meta_search" #=> true
1.9.3p125 :003 > Document.search
# I still get tire, all is well
# Tire loaded, meta_search is not loaded
1.9.3p125 :001 > require "meta_search" #=> true
1.9.3p125 :002 > Document.search
Document Load (1.8ms) SELECT "documents".* FROM "documents"
# I get meta_search, even though Document.search was already defined!
# Tire loaded, meta_search is not loaded, RAILS_ENV="production"
Loading production environment (Rails 3.2.2)
1.9.3p125 :001 > require "meta_search"
=> true
1.9.3p125 :002 > Document.search
# I get tire!
我对此的解释是,当类未实际加载时,meta_search如何检测搜索是否已定义。万岁!
答案 0 :(得分:6)
相关的2行:
https://github.com/ernie/meta_search/blob/master/lib/meta_search.rb#L55
https://github.com/ernie/meta_search/blob/master/lib/meta_search/searches/active_record.rb#L46
我不认为这是一个错误,它只是事物的方式。
方案3中的在开发环境中,您不预加载模型。当您需要“meta_search”时,它会在ActiveRecord::Base
上定义“搜索”。然后你说加载模型的Document
将首先继承定义的搜索方法,所以当它包含轮胎搜索模块时,它会将搜索别名留给元搜索。
在生产模式(场景4)和场景2中,您在元搜索之前预加载文档模型,因此Tire将定义搜索。现在要求元搜索只会对新加载的类产生影响。
您可以看到定义宝石的顺序不计算在内。但是你可以在gem需要之后取消定义搜索方法。
# application.rb
# ...
Bundler.require(:default, Rails.env) if defined?(Bundler)
# now move search out of the way
ActiveRecord::Base.instance_eval { undef :search }
因此,任何时候我们加载模型类并包含轮胎,搜索将在开发和生产中正确地进入轮胎状态。
这并不理想,因为非轮胎模型的搜索方法不会委托给元搜索,事实上它不会被定义。所以第二个解决方案可能是最好的:在这里你用一个在运行时检查轮胎的方法覆盖搜索方法:
class ActiveRecord::Base
def self.search(*args, &block)
if respond_to?(:tire)
tire.search(*args, &block)
else
metasearch(*args, &block)
end
end
end
这有帮助吗?
答案 1 :(得分:1)
简短但不满意的答案:在Gemfile中将轮胎移到active_admin上方。如果已经定义了search
方法,meta_search和轮胎都会避免定义tire.search
方法,因此首先要确保轮胎已加载。
或者,在加载轮胎和meta_search之后(例如在Rails初始化程序中),您可以重新定义ActiveRecord :: Base.search以执行method_defined?
:
search
检查是否定义了实例方法,而在这种情况下Document.methods.include?(:search)
是一个类方法。查看是否定义类方法的唯一真正方法是search
。同样,当您重新定义def self.search
时,是否确保将其设为类方法(例如{{1}})?
不幸的是,“我的依赖关系依赖于猴子修补我的代码”问题是Ruby中的一个主要烦恼,并且在某种程度上是不可避免的。图书馆作者可以灵活地做他们想要的事情,但是他们经常滥用权力来“让事情变得更容易”。