4
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在祖先链中,所以bar从不触及返回 0 的自定义方法。

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

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 可以工作?或者完全做到这一点的另一种方式?

4

1 回答 1

9

你确定你想要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
于 2013-07-03T16:26:43.390 回答