Is there a clean API for resetting instance variables on 'reload' in ActiveRecord?

泪湿孤枕 提交于 2019-12-19 05:10:26

问题


In an ActiveRecord::Base model, I can reset the state of the model to what it was when I got it from the database with reload, as long as the attribute I'm setting maps to a table column:

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"

But if I add a custom attribute, the only way I've found to have it act the same is like this:

class User < ActiveRecord::Base
  attr_accessor :user_agent

  def reload
    super
    self.user_agent = nil
    self
  end
end

My question is, is there some API to make non-database-column-attributes reset on reload? Something like:

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

Does that exist in Rails somewhere?


回答1:


ActiveRecord does not provide a way to do this, it can only acts on the model attributes.

That being said, I think a more elegant way to do it would be to loop over the ivars and set them to whatever you like :

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

Note that we skip @attributes because AR is taking care of it when you reload the attributes.




回答2:


Rework Jean-Do's answer slightly. It doesn't break default instance_variables and relations.

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



回答3:


I took gayavat's answer and reworked it into my test_helper.rb file, because I didn't want to override the usual #reload method.

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

When I need to reload something in a test I just call reload_ivars(object).



来源:https://stackoverflow.com/questions/5602443/is-there-a-clean-api-for-resetting-instance-variables-on-reload-in-activerecor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!