加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby-on-rails – 包含InstanceMethods模块时覆盖attr_accessor

发布时间:2020-12-17 04:13:38 所属栏目:百科 来源:网络整理
导读:我有一个ActiveRecord扩展(缩写): module HasPublishDates def self.included(base) base.send :extend,ClassMethods end module ClassMethods def has_publish_dates(*args) attr_accessor :never_expire include InstanceMethods end end module Instance
我有一个ActiveRecord扩展(缩写):
module HasPublishDates
  def self.included(base)
    base.send :extend,ClassMethods
  end

  module ClassMethods
    def has_publish_dates(*args)
      attr_accessor :never_expire

      include InstanceMethods
    end
  end

  module InstanceMethods
    def never_expire=(value)
      @never_expire = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
    end

    def another_instance_method
      'something to return'
    end
  end
end

ActiveSupport.on_load(:active_record) do
  include HasPublishDates
end

可以像这样调用:

class MyModel < ActiveRecord::Base
  has_publish_dates
  ...
end

我们的想法是,never_expire =应该覆盖由attr_accessor:never_expire定义的setter.但是,它似乎没有工作:

m = MyModel.new
m.never_expire            #=> nil
m.never_expire = '1'      #=> '1'
m.never_expire            #=> '1' should be true if never_expire= has been overridden
m.another_instance_method #=> 'something to return' works as expected

正如您所看到的,正在包含another_instance_method并且正在按预期工作但never_expire =并未像我预期的那样覆盖setter.

如果我将HasPublishDates更改为使用class_eval,那么它将按预期工作:

module HasPublishDates
  ...
  module ClassMethods
    def has_publish_dates(*args)
      ...
      class_eval do
        def never_expire=(value)
          @never_expire = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
        end

        def another_instance_method
          'something to return'
        end
      end
    end
  end
end
...

m = MyModel.new
m.never_expire            #=> nil
m.never_expire = '1'      #=> true
m.never_expire            #=> true
m.another_instance_method #=> 'something to return'

我想这是因为InstanceMethods是在attr_accessor之前定义的:never_expire是由has_publish_dates调用的.

虽然我认为class_eval是一种优雅的做事方式,但我也喜欢将我的实例方法暴露给文档的想法,所以当另一个开发人员试图使用我的代码时,没有“魔力”.

无论如何我可以在这种情况下使用include InstanceMethods方法吗?

解决方法

在继续使用包含的模块和超类方法的方法之前,Ruby中的调用顺序以普通实例方法开始.由attr_accessor创建的never_expire =方法最终成为一个实例方法,因此调用它而不是InstanceMethods模块的方法.如果你使用attr_reader,那么没有定义never_expire = instance方法,它将按你的意愿工作.

也就是说,使用那些额外的ClassMethods和InstanceMethods模块,你所做的事情比他们需要的更复杂.只需按照预期使用模块:

module HasPublishDates
  attr_reader :never_expire

  def never_expire=(value)
    @never_expire = ActiveRecord::ConnectionAdapters::Column.value_to_boolean(value)
  end
end

class MyModel < ActiveRecord::Base
  include HasPublishDates
end

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读