gpt4 book ai didi

ruby-on-rails - 包含 InstanceMethods 模块时覆盖 attr_accessor 的 setter 方法

转载 作者:数据小太阳 更新时间:2023-10-29 06:57:39 26 4
gpt4 key购买 nike

我有一个 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_expirehas_publish_dates 调用之前定义的。

虽然我认为 class_eval 是一种优雅的做事方式,但我也喜欢将我的实例方法公开用于文档的想法,这样当其他开发人员尝试使用我的代码时就没有“魔法”了.

在这种情况下,我是否可以使用 include InstanceMethods 方法?

最佳答案

Ruby 中的调用顺序从普通实例方法开始,然后再继续包含模块和父类(super class)方法的方法。 attr_accessor 创建的 never_expire= 方法最终成为一个实例方法,因此调用它而不是 InstanceMethods 模块的方法。如果您改为使用 attr_reader,则不会定义任何 never_expire= 实例方法,它将按您的预期工作。

就是说,使用那些额外的 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

关于ruby-on-rails - 包含 InstanceMethods 模块时覆盖 attr_accessor 的 setter 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8043014/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com