Есть ли чистый API для сброса переменных экземпляра при «перезагрузке» в ActiveRecord? - PullRequest
14 голосов
/ 09 апреля 2011

В модели 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 ]

14 голосов
/ 09 апреля 2011

ActiveRecord не предоставляет способ сделать это, он может действовать только на атрибуты модели.

При этом, я думаю, что более элегантный способ сделать это - перебрать ивары и установить их на то, что вам нравится:

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 заботится об этом при перезагрузке атрибутов.

4 голосов
/ 16 февраля 2013

Немного переработал ответ Жан-До. Это не нарушает значения по умолчанию 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
1 голос
/ 11 марта 2013

Я взял ответ 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).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...