如何阻止meta_search在我的模型上定义搜索?

Jor*_*rds 3 ruby-on-rails meta-search tire

我正在使用active_admin,这会将meta_search引入我的项目.(我不想用于其他任何事情).

它似乎是在我的所有模型上定义搜索方法,这意味着当我包括轮胎时,我不能使用它的搜索方法.

它如何定义方法似乎有些奇怪 - method_defined?说没有定义搜索方法,但是当我调用它时,我得到了meta_search.即使我在类中定义自己的搜索方法,当我调用Document.search时,我仍然会得到meta_search.

编辑:我对处理这类事情的一般方法感兴趣 - 我已经通过使用Model.tire.search解决了这个特殊问题(因为轮胎也可以通过这种方式访问​​),但我仍然讨厌那个宝石我甚至不使用可以强迫我在我的项目的其余部分使用解决方法.

编辑:我不知道在答案的答案中包含代码块的好方法,所以我会把它放在这里.

# 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!
Run Code Online (Sandbox Code Playgroud)

我对此的解释是,当类没有实际加载时,meta_search如何检测搜索是否已定义.万岁!

Vik*_*rón 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 }
Run Code Online (Sandbox Code Playgroud)

因此,任何时候我们加载一个模型类并包括轮胎,搜索将在开发和生产中正确地进入轮胎状态.

这并不理想,因为非轮胎模型的搜索方法不会委托给元搜索,实际上它不会被定义.所以第二个解决方案可能是最好的:在这里你用一个在运行时检查轮胎的方法覆盖搜索方法:

class ActiveRecord::Base
  def self.search(*args, &block)
    if respond_to?(:tire)
       tire.search(*args, &block)
    else
       metasearch(*args, &block)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

这有帮助吗?