2012-07-19 29 views
1

这里的交互有点复杂,请耐心等待。 我正在使用Spree。 Spree在其一些模型中使用了delegate_belongs_to,包括“Spree :: Variant”。 'delegate_belongs_to:product,:available_on(...)'在原始类体中被调用。我如何重写一个宝石添加到ActiveRecord :: Base的类方法(在我的装饰器中)

我希望变体能够拥有自己的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 

我宁愿不重写整个variant类删除此一个参数。这是我最近的尝试之一:

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中,如果执行顺序有问题,或者是什么,但我似乎无法重写此方法。我在这里无法理解什么?

谢谢。

+0

我正在研究迄今为止提供的解决方案。一个注意,在轨道控制台'Spree :: Product.method(:delegate_belongs_to).source_location '给了我原来的位置,'Spree :: Variant.method(:delegate_belongs_to).source_location'给了我在我的装饰器中的定义线。方法中的断点虽然没有做任何事情。 – 2012-07-19 21:04:42

回答

0

这是不是一个真正的答案,我指出我曾尝试

,我不知道有多少,这将有所帮助,但我把你的代码,并简化了一点,看是否覆盖该方法可以正常工作,这意味着你的方法是正确的,如果你直接覆盖类,那么它会调用新的方法。

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" 
0

我通常在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个月前导轨3.0。 9和spree_core 0.60.1所以我的回答对你来说可能没用,但也许会给你一些方向。

+0

delegate_belongs_to是从Variant类的正文中调用的方法(如'has_many'或'belongs_to')。我仍然在尝试使用这种方法。问题在于,旧的delegate_belongs_to在被切换之前至少被调用一次,并且正在进行无法调用的修改。我想我可能不得不重写整个变体类来删除这一个参数。 – 2012-07-19 21:39:52

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 
+0

是的,它似乎没有任何影响。我使用的是class_eval,因为他们推荐将其用于扩展Spree功能:http://guides.spreecommerce.com/logic_customization.html – 2012-07-19 21:15:03

+0

您是否在使用它之前尝试覆盖它? – 2012-07-19 21:18:32

1

我结束了刚刚覆盖Spree :: Variant在我自己的应用程序/模型目录。

我真的不希望这样做是为了删除一个参数,但事实上,spree模型似乎在实例化中加载到内存中,并且由于Ruby具有可执行类体,原始的delegate_belongs_to调用被触发(并触发一些副作用),然后才能切换出来。

该方法正在被覆盖,我可以证实,但到时候已经太迟了。我尝试设置一个初始化程序来解决这个问题并不成功。

据我所知,任何面临类似情况的人都必须替换整个班级。如果有人有更好的解决方案,我想留下这个问题。感谢您的回应。

0

对于任何寻找工作解决方案的人来说,移除getter和setter会恢复到ActiveRecord关联。

`DATETIME_add_to_variant.rb`: 
class AddToVariant < ActiveRecord::Migration 
    def change 
     add_column :spree_variants, :description, :text 
     add_column :spree_variants, :available_on, :datetime 
    end 
end 

`variant_decorator.rb`: 
Spree::Variant.class_eval do 
    remove_method :description 
    remove_method :description= 

    remove_method :available_on 
    remove_method :available_on= 
end 
相关问题