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

时间:2011-04-09 02:06:56

标签: ruby-on-rails activerecord

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中是否存在某个地方?

3 个答案:

答案 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)