如何解决在rails中的ActiveRecord对象中,跟踪非持久属性的脏状态
|| 我有一个从ActiveRecord继承的对象,但是它的属性不能持久保存在数据库中,例如: class Foo < ActiveRecord::Base
attr_accessor :bar
end
我希望能够使用ActiveModel Dirty提供的\'bar_changed?\'之类的方法来跟踪\'bar \'的更改。问题是,当我尝试在docs上对此对象实现Dirty时,由于ActiveRecord和ActiveModel都已定义define_attribute_methods
,但参数数量不同,因此我收到了错误消息,因此我尝试调用ѭ2时出错。
在包含ActiveModel::Dirty
之前,我曾尝试过对define_attribute_methods
进行别名处理,但是没有运气:我得到了一个未定义的方法错误。
有关如何处理此问题的任何想法?当然,我可以手动编写所需的方法,但是我想知道是否可以通过将ActiveModel功能扩展到ActiveRecord无法处理的属性来使用Rails模块。
解决方法
我正在使用
attribute_will_change!
方法,并且一切正常。
它是ѭ6中定义的私有方法,但ActiveRecord在所有模型中都将其混合。
这是我最终在模型类中实现的:
def bar
@bar ||= init_bar
end
def bar=(value)
attribute_will_change!(\'bar\') if bar != value
@bar = value
end
def bar_changed?
changed.include?(\'bar\')
end
init_bar
方法仅用于初始化属性。您可能需要也可能不需要。
我不需要指定任何其他方法(例如define_attribute_methods
)或包含任何模块。
您必须自己重新实现某些方法,但是至少行为与ActiveModel基本上是一致的。
我承认我还没有对它进行彻底的测试,但是到目前为止,我还没有遇到任何问题。
,我想出了一个对我有用的解决方案...
将此文件另存为lib/active_record/nonpersisted_attribute_methods.rb
:https://gist.github.com/4600209
然后,您可以执行以下操作:
require \'active_record/nonpersisted_attribute_methods\'
class Foo < ActiveRecord::Base
include ActiveRecord::NonPersistedAttributeMethods
define_nonpersisted_attribute_methods [:bar]
end
foo = Foo.new
foo.bar = 3
foo.bar_changed? # => true
foo.bar_was # => nil
foo.bar_change # => [nil,3]
foo.changes[:bar] # => [nil,3]
但是,当我们这样做时,似乎会收到警告:
DEPRECATION WARNING: You\'re trying to create an attribute `bar\'. Writing arbitrary attributes on a model is deprecated. Please just use `attr_writer` etc.
所以我不知道这种方法在Rails 4中会失效还是难以解决...
,ActiveRecord
具有#attribute
方法(源),一旦从您的类中调用该方法,它将使ActiveModel::Dirty
创建诸如bar_was
,bar_changed?
等许多方法。
因此,您必须在从ActiveRecord
扩展的任何类中调用attribute :bar
(对于最新版本的Rails,则是ApplicationRecord
),以便在bar
上创建这些辅助方法。
编辑:请注意,此方法不应与attr_accessor :bar
混合使用
编辑2:另一个要注意的是,保存时,用attribute
(例如attribute :bar,:string
)定义的非持久属性将被删除。如果保存后需要attrs徘徊(就像我一样),则可以(小心地)与attr_reader
混合,如下所示:
attr_reader :bar
attribute :bar,:string
def bar=(val)
super
@bar = val
end
,自己编写bar =方法,并使用实例变量跟踪更改。
def bar=(value)
@bar_changed = true
@bar = value
end
def bar_changed?
if @bar_changed
@bar_changed = false
return true
else
return false
end
end
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。