跟踪 Rails 中 ActiveRecord 对象中非持久属性的脏信息
我有一个继承自 ActiveRecord 的对象,但它有一个未保留在数据库中的属性,例如:
class Foo < ActiveRecord::Base
attr_accessor :bar
end
我希望能够使用 ActiveModel 提供的“bar_changed?”等方法来跟踪“bar”的更改肮脏的。问题是,当我尝试在此对象上实现 Dirty 时,如 docs 中所述,我'我收到错误,因为 ActiveRecord 和 ActiveModel 都定义了 define_attribute_methods
,但参数数量不同,因此在尝试调用 define_attribute_methods [:bar]
时收到错误。
在包含 ActiveModel::Dirty
之前,我尝试过使用别名 define_attribute_methods
,但没有成功:我收到未定义方法错误。
关于如何处理这个问题有什么想法吗?当然,我可以手动编写所需的方法,但我想知道是否可以使用 Rails 模块,通过将 ActiveModel 功能扩展到 ActiveRecord 未处理的属性来实现。
I have an object that inherits from ActiveRecord, yet it has an attribute that is not persisted in the DB, like:
class Foo < ActiveRecord::Base
attr_accessor :bar
end
I would like to be able to track changes to 'bar', with methods like 'bar_changed?', as provided by ActiveModel Dirty. The problem is that when I try to implement Dirty on this object, as described in the docs, I'm getting an error as both ActiveRecord and ActiveModel have defined define_attribute_methods
, but with different number of parameters, so I'm getting an error when trying to invoke define_attribute_methods [:bar]
.
I have tried aliasing define_attribute_methods
before including ActiveModel::Dirty
, but with no luck: I get a not defined method error.
Any ideas on how to deal with this? Of course I could write the required methods manually, but I was wondering if it was possible to do using Rails modules, by extending ActiveModel functionality to attributes not handled by ActiveRecord.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我正在使用
attribute_will_change!
方法,一切似乎运行良好。它是在
active_model/dirty.rb
中定义的私有方法,但 ActiveRecord 将其混合在所有模型中。这就是我最终在模型类中实现的内容:
init_bar
方法仅用于初始化属性。您可能需要也可能不需要它。我不需要指定任何其他方法(例如
define_attribute_methods
)或包含任何模块。您确实必须自己重新实现一些方法,但至少行为将与 ActiveModel 基本一致。
我承认我还没有彻底测试它,但到目前为止我还没有遇到任何问题。
I'm using the
attribute_will_change!
method and things seem to be working fine.It's a private method defined in
active_model/dirty.rb
, but ActiveRecord mixes it in all models.This is what I ended up implementing in my model class:
The
init_bar
method is just used to initialise the attribute. You may or may not need it.I didn't need to specify any other method (such as
define_attribute_methods
) or include any modules.You do have to reimplement some of the methods yourself, but at least the behaviour will be mostly consistent with ActiveModel.
I admit I haven't tested it thoroughly yet, but so far I've encountered no issues.
ActiveRecord
具有#attribute
方法 (source) 一旦从您的类调用,将让ActiveModel::Dirty
创建方法,例如bar_was
、bar_changed?
和 许多其他。因此,您必须在从
ActiveRecord
(对于最新版本的 Rails 为ApplicationRecord
)扩展的任何类中调用attribute :bar
,以便在bar
上创建这些辅助方法。编辑:请注意,此方法不应与
attr_accessor :bar
混合编辑 2:另一个注意事项是使用
attribute
定义的非持久属性(例如attribute :bar, : string
)将在保存时被吹走。如果您需要 attrs 在保存后保留(就像我所做的那样),您实际上可以(小心)与 attr_reader 混合,如下所示:ActiveRecord
has the#attribute
method (source) which once invoked from your class will letActiveModel::Dirty
to create methods such asbar_was
,bar_changed?
, and many others.Thus you would have to call
attribute :bar
within any class that extends fromActiveRecord
(orApplicationRecord
for most recent versions of Rails) in order to create those helper methods uponbar
.Edit: Note that this approach should not be mixed with
attr_accessor :bar
Edit 2: Another note is that unpersisted attributes defined with
attribute
(egattribute :bar, :string
) will be blown away on save. If you need attrs to hang around after save (as I did), you actually can (carefully) mix withattr_reader
, like so:我找到了一个适合我的解决方案...
将此文件另存为
lib/active_record/nonpersisted_attribute_methods.rb
: https://gist.github.com/4600209然后你可以这样做:
但是,当我们这样做时,看起来我们会收到警告:
所以我不知道这种方法在 Rails 4 中是否会被破坏或者变得更加困难......
I figured out a solution that worked for me...
Save this file as
lib/active_record/nonpersisted_attribute_methods.rb
: https://gist.github.com/4600209Then you can do something like this:
However, it looks like we get a warning when we do it this way:
So I don't know if this approach will break or be harder in Rails 4...
自己编写 bar= 方法并使用实例变量来跟踪更改。
Write the bar= method yourself and use an instance variable to track changes.