繁体   English   中英

如何覆盖gem添加到ActiveRecord :: Base的类方法(在我的装饰器中)

[英]How can I override a class method that a gem is adding to ActiveRecord::Base (in my decorator)

这里的互动有点复杂,所以请耐心等待。 我正在和Spree合作。 Spree在其某些模型中使用delegate_belongs_to,包括'Spree :: Variant'。 '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  

我宁愿不覆盖整个变体类来删除这一个参数。 这是我最近的一次尝试:

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

谢谢。

我通常在lib中执行此操作,因此我确信在所有初始化程序之后对我的更改进行评估。

  1. 允许在application.rb加载lib文件

     # ... 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个月前我用rails 3.0.9和spree_core 0.60.1做了类似的事情,所以我的答案对你来说没用,但也许会给你一些指示。

我不认为我完全理解你的问题,但每当我看到有人使用class_eval或alias_method时,我认为必须有更好的方法。 您是否尝试过覆盖课程中的方法而只是调用super?

class MyModel < ActiveRecord::Base
  def self.delegate_belongs_to(association, *attrs)
    attrs.delete [:available_on]
    super(association, attrs)
  end
end

我最终在我自己的app / models目录中覆盖了Spree :: Variant。

我真的宁愿不为了删除一个参数而这样做,但事实是spree模型似乎在实例化时被加载到内存中,并且由于Ruby有可执行类主体,原始的delegate_belongs_to调用被触发(和在我将其切换之前触发了许多副作用。

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

据我所知,任何面临类似情况的人都必须更换整个班级。 如果有人有更好的解决方案,我想暂时搁置这个问题。 谢谢你的回复。

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

我不确定这会有多大帮助,但我拿了你的代码并简化了一下,看看覆盖方法是否有效,这意味着你的方法是正确的,如果你直接覆盖类,那么它会调用新方法。

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"

对于寻找工作解决方案的任何人,删除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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM