在ActiveRecord::Base
模型中,只要我设置的属性映射到一个模型,我就可以将模型的状态重置为从reload
的数据库中获取模型的状态。表格列:
user = User.first
user.email #=> "email@domain.com"
user.email = "example@site.com"
user.email #=> "example@site.com"
user.reload
user.email #=> "email@domain.com"
但是如果我添加一个自定义属性,我发现让它行为相同的唯一方法就是这样:
class User < ActiveRecord::Base
attr_accessor :user_agent
def reload
super
self.user_agent = nil
self
end
end
我的问题是,是否有一些API可以在重新加载时重置非数据库列属性?类似的东西:
class User < ActiveRecord::Base
# this
reloadable_attr_accessor :user_agent
# or this
def user_agent
@user_agent
end
def user_agent=(value)
set_instance_var_that_resets_on_reload("@user_agent", value)
end
end
Rails中是否存在某个地方?
答案 0 :(得分:14)
ActiveRecord没有提供这样做的方法,它只能作用于模型属性。
话虽如此,我认为一种更优雅的方式就是绕过ivars并将它们设置为你喜欢的任何东西:
class User < ActiveRecord::Base
def reload(options = nil)
super
self.instance_variables.each do |ivar|
next if ivar == '@attributes'
self.instance_variable_set(ivar, nil)
end
end
end
请注意,我们跳过@attributes,因为AR在您重新加载属性时正在处理它。
答案 1 :(得分:4)
重做Jean-Do的回答。它不会破坏默认的instance_variables和关系。
after_initialize do
@default_instance_variables = instance_variables
end
def reload(options = nil)
super
self.instance_variables.each do |ivar|
if ivar == :'@default_instance_variables' ||
@default_instance_variables.include?(ivar)
next
end
remove_instance_variable(ivar)
end
self
end
答案 2 :(得分:1)
我接受了gayavat的回答并将其重新编写到我的test_helper.rb
文件中,因为我不想覆盖通常的#reload方法。
class ActiveRecord::Base
attr_accessor :default_instance_variables
after_initialize do
@default_instance_variables = instance_variables
end
end
def reload_ivars(obj)
obj.reload
obj.instance_variables.each do |ivar|
if ivar == :'@default_instance_variables' ||
obj.default_instance_variables.include?(ivar)
next
end
obj.send(:remove_instance_variable, ivar)
end
end
当我需要在测试中重新加载某些内容时,我只需调用reload_ivars(object)
。