【问题标题】:How do I override an attr_accessor getter from a module?如何覆盖模块中的 attr_accessor getter?
【发布时间】:2013-07-01 10:53:28
【问题描述】:
module HasUrl
  extend ActiveSupport::Concern

  included do
    attr_accessor :bar
  end

  def bar
    0
  end
end

class Foo < ActiveRecord::Base
  include HasUrl
end

bar 属性不存储在数据库中,而是在表单中使用(使用 SimpleForm 的f.input)。我想覆盖这个方法的getter,这样我就可以根据其他属性设置bar,并让表单正确地预填充值。

问题是在这样的包含块中使用attr_accessor 会在Foo 类上设置getter。由于该模块包含在祖先链中的Foo 之上,因此永远不会触及返回0 的自定义bar 方法。

解决这个问题的一种方法是

class Foo < ActiveRecord::Base
  include HasUrl

  def bar
    super
  end
end

但我想避免这个额外的步骤。我只想包含该模块并让它“工作”。另一种选择是在我的表单中使用不同的助手(f.input_field 等),但我无法利用 SimpleForm 的包装器。

Module#prepend 也不能解决我的问题,因为HasUrl 还定义了一些其他的东西(特别是 ActiveRecord 回调)。如果我预先添加,这些回调会导致错误:

NoMethodError: undefined method `_run_...__find__...__callbacks`

有没有办法绕过这个错误,以便 prepend 可以工作?或者另一种方法来完全做到这一点?

【问题讨论】:

    标签: ruby-on-rails ruby module ruby-2.0


    【解决方案1】:

    您确定要attr_accessor 吗? attr_writer 不够吗?

    require 'active_support/all'
    
    module HasUrl
      extend ActiveSupport::Concern
    
      included do
        attr_writer :bar
      end
    
      def bar
        0
      end
    end
    
    class Foo
      include HasUrl
    end
    
    p Foo.new.bar
    

    无论如何,如果你真的想使用attr_accessor,这应该可以:

    require 'active_support/all'
    
    module HasUrl
      extend ActiveSupport::Concern
    
      included do
        attr_accessor :bar
        define_method :bar do
          0
        end
      end
    end
    
    class Foo
      include HasUrl
    end
    
    p Foo.new.bar
    

    【讨论】:

    • 没错,如果你覆盖了getter,那么使用attr_writer就足够了
    • 谢谢。我之前使用过attr_writer,但它导致我的表单出现问题。这是因为我在 attr_accessor 行上有两个属性,其中一个我确实需要 getter。阅读错误消息时,我只是愚蠢。此外,似乎前置问题已在 p195:github.com/rails/rails/issues/10899 中修复,因此也可以正常工作(我正在处理 p0)。
    猜你喜欢
    • 1970-01-01
    • 2014-03-17
    • 2015-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-26
    • 1970-01-01
    相关资源
    最近更新 更多