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

Lan*_*ard 15 activerecord ruby-on-rails

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"
Run Code Online (Sandbox Code Playgroud)

但是,如果我添加一个自定义属性,我发现让它行为相同的唯一方法是这样的:

class User < ActiveRecord::Base
  attr_accessor :user_agent

  def reload
    super
    self.user_agent = nil
    self
  end
end
Run Code Online (Sandbox Code Playgroud)

我的问题是,是否有一些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
Run Code Online (Sandbox Code Playgroud)

在某个地方Rails中存在吗?

小智 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
Run Code Online (Sandbox Code Playgroud)

请注意,我们跳过@attributes,因为AR在重新加载属性时会处理它.

  • 谢谢你的提示!但它使所有协会都是零:( (2认同)

gay*_*vat 6

稍微修改 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
Run Code Online (Sandbox Code Playgroud)