1

ここでのやり取りは少し複雑ですので、ご容赦ください。私はSpreeで働いています。Spree は、'Spree::Variant' を含む一部のモデルで delegate_belongs_to を使用しています。'delegate_belongs_to :product, :available_on (...)' は元のクラス本体で呼び出されています。

バリアントが独自の available_on 日付を持つことができるようにしたいと思います。delegate_belongs_to は次のように自分自身を注入しています:

module DelegateBelongsTo
  extend ActiveSupport::Concern
  module ClassMethods
    #...
    def delegate_belongs_to(association, *attrs)     
      #...
    end
  end
end

ActiveRecord::Base.send :include, DelegateBelongsTo  

この 1 つの引数を削除するためにバリアント クラス全体をオーバーライドすることは避けたいと思います。これは私の最近の試みの1つです:

Spree::Variant.class_eval do
  class << self
    alias_method :original_dbt, :delegate_belongs_to

    def delegate_belongs_to(association, *attrs)
      attrs.delete [:available_on]
      original_dbt(association, attrs)
    end
  end

  attr_accessible :available_on
  #...
end

私はこれについていくつかのバリエーションを試しました。それがclass_evalにあるからなのか、実行順序に問題があるのか​​ どうかはわかりませんが、このメソッドをオーバーライドできないようです。ここで何が理解できていないのですか?

ありがとう。

4

5 に答える 5

1

私は通常libでそれを行うので、私の変更はすべての初期化の後で評価されると確信しています。

  1. でlibファイルをロードできるようにするapplication.rb

    # ...
    module App
      class Application < Rails::Application
        # ...        
        config.autoload_paths += %W(#{config.root}/lib)
        # ...
        require 'spree_variants'
      end
    end
    
  2. lib/spree_variants.rbコンテンツを含むファイルを作成する

    require 'spree_core'
    
    module SpreeOldPriceProducts
      class Engine < Rails::Engine
        def self.activate
          Variant.class_eval do
            alias_method :original_dbt, :delegate_belongs_to
    
            def delegate_belongs_to(association, *attrs)
              attrs.delete [:available_on]
              original_dbt(association, attrs)
            end
          end
        end
    
        config.to_prepare &method(:activate).to_proc
      end
    end
    

私は約2か月前にrails3.0.9とspree_core0.60.1を使ってそのようなことをしたので、私の答えは役に立たないかもしれませんが、おそらくいくつかの方向性を示しています。

于 2012-07-19T20:55:54.350 に答える
1

これは実際には答えではありません。私が試したことを指摘しています

これがどれほど役立つかはわかりませんが、コードを少し単純化して、メソッドの上書きが機能するかどうかを確認しました。これは、メソッドが正しいことを意味し、クラスを直接上書きすると、新しい方法。

module DelegateBelongsTo

  module ClassMethods
    def delegate_belongs_to(association, *attrs)     
      p "METHOD INSIDE MODULE"
    end
  end

  def self.included(base)
    base.extend(ClassMethods)
  end
end

module Spree
  class Variant
    include DelegateBelongsTo

    def self.some_method
      delegate_belongs_to("foo", "bar")
    end
  end
end

Spree::Variant.some_method  #METHOD INSIDE MODULE


Spree::Variant.class_eval do
  class << self
    alias_method :original_dbt, :delegate_belongs_to
    def delegate_belongs_to(association, *attrs)
       p "OVERWRITTEN METHOD"
      original_dbt(association, *attrs)
    end
 end
end

Spree::Variant.some_method # "OVERWRITTEN METHOD", "METHOD INSIDE MODULE"
于 2012-07-19T20:48:52.233 に答える
1

私は自分の app/models ディレクトリで Spree::Variant をオーバーライドするだけになりました。

引数を 1 つ削除するためにこれを実行しない方がよかったのですが、問題は、spree モデルがインスタンス化時にメモリに読み込まれるように見え、Ruby には実行可能なクラス本体があるため、元の delegate_belongs_to 呼び出しが発生することです (そして切り替える前に、多くの副作用を引き起こします)。

メソッドがオーバーライドされていることは確認できますが、それまでには手遅れです。これを回避するためにイニシャライザをセットアップしようとしましたが、うまくいきませんでした。

私の知る限り、同様の状況に直面している人は、クラス全体を交換する必要があります. 誰かがより良い解決策を持っている場合に備えて、この質問を少し開いたままにしたいと思います。回答ありがとうございます。

于 2012-07-20T01:10:38.317 に答える
1

私はあなたの問題を完全に理解しているとは思いませんが、誰かが class_eval または alias_method を使用しているのを見るたびに、もっと良い方法が必要だと思います. クラスのメソッドをオーバーライドして、スーパーを呼び出してみましたか?

class MyModel < ActiveRecord::Base
  def self.delegate_belongs_to(association, *attrs)
    attrs.delete [:available_on]
    super(association, attrs)
  end
end
于 2012-07-19T21:02:12.783 に答える