是否有一个干净的API用于在ActiveRecord中的’reload’上重置实例变量?

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中存在吗?

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在重新加载属性时会处理它。

重做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 

我接受了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)