3

私はactive_adminを使用しており、それが私のプロジェクトにmeta_searchをもたらしています。(これは他の目的には使用したくない)。

すべてのモデルで検索方法を定義しているようです。つまり、タイヤを含めると、その検索方法を使用できなくなります。

メソッドの定義方法にも奇妙なことがあるようです--method_defined?検索メソッドが定義されていないことを示していますが、それを呼び出すと、meta_searchが取得されます。クラスで独自の検索メソッドを定義しても、Document.searchを呼び出すと、meta_searchが取得されます。

編集:私はこの種のものを扱う一般的な方法に興味があります-私はModel.tire.searchを使用してこの特定の問題を解決しました(タイヤもその方法でアクセスできるため)、しかし私はまだその宝石が嫌いですm使用していなくても、プロジェクトの残りの部分で回避策を使用せざるを得なくなる可能性があります。

編集:回答への回答にコードブロックを含める良い方法がわからないので、ここに配置します。

# 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が検出する方法にバグがあるということです。やったー!

4

2 に答える 2

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'が必要な場合は、で'search'を定義しますActiveRecord::Base。次にDocument、モデルをロードするが、最初に定義された検索メソッドを継承するため、Tire検索モジュールが含まれている場合、検索はメタ検索のエイリアスのままになります。

本番モード(シナリオ4)およびシナリオ2では、メタ検索の前にドキュメントモデルをプリロードして、Tireが検索を定義するようにします。現在、メタ検索を要求することは、新しくロードされたクラスにのみ影響します。

宝石が定義されている順序はカウントされないことがわかります。ただし、gemrequireの後で検索方法の定義を解除することができます。

# application.rb
# ...
Bundler.require(:default, Rails.env) if defined?(Bundler)
# now move search out of the way
ActiveRecord::Base.instance_eval { undef :search }

したがって、後でモデルクラスをロードしてタイヤを含めると、開発と本番の両方で検索が正しくタイヤに反映されます。

非タイヤモデルの検索方法はメタ検索に委任されないため、これは理想的ではありません。実際、定義されません。したがって、おそらく2番目の解決策が最適です。ここでは、検索メソッドを実行時にタイヤをチェックするメソッドで上書きします。

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

これは役に立ちますか?

于 2012-05-30T20:09:34.587 に答える
1

短いですが、満足のいく答えではありません。Gemfileのactive_adminの上にタイヤを移動します。meta_searchとtireはどちらも、searchメソッドがすでに定義されている場合はメソッドの定義を回避するため、最初にタイヤをロードすることでメソッドを定義する必要があります。

または、 tireとmeta_searchの両方がロードされた後(たとえば、Rails初期化子で)、ActiveRecord::Base.searchを再定義して次のことを行うことができますtire.search

method_defined?インスタンスメソッドが定義されているかどうかを確認しますがsearch、この場合はクラスメソッドです。クラスメソッドが定義されているかどうかを確認する唯一の実際の方法はですDocument.methods.include?(:search)。同様に、再定義したときに、searchそれをクラスメソッド(例def self.search)にすることを確認しましたか?

残念ながら、「依存関係の依存関係はコードにモンキーパッチを適用することです」という問題は、Rubyの大きな問題であり、やや避けられません。図書館の作者は彼らがやりたいことをするために多くの柔軟性を与えられていますが、彼らはしばしば「物事を使いやすくする」ために彼らの力を乱用します。

于 2012-05-30T06:03:24.487 に答える