Rails 3 comprobar si el atributo ha cambiado


Es necesario comprobar si un bloque de atributos ha cambiado antes de la actualización en Rails 3.

Street1, street2, city, state, zipcode

Sé que podría usar algo como

if @user.street1 != params[:user][:street1]
  then do something....
end

Pero ese fragmento de código será MUY largo. ¿Hay una manera más limpia?

Author: pcasa, 2011-02-19

5 answers

Echa un vistazo a ActiveModel::Dirty (disponible en todos los modelos por defecto). La documentación es muy buena, pero te permite hacer cosas como:

@user.street1_changed? # => true/false
 264
Author: Peter Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-19 13:57:59

Así es como resolví el problema de comprobar si hay cambios en múltiples atributos.

attrs = ["street1", "street2", "city", "state", "zipcode"]

if (@user.changed & attrs).any?
  then do something....
end

El changed method devuelve una matriz de los atributos modificados para ese objeto.

Ambos @user.changed y attrs son matrices para que pueda obtener la intersección (ver ary & other ary método). El resultado de la intersección es una matriz. Al llamar a any? en la matriz, obtengo true si hay al menos una intersección.

También muy útil, el changed_attributes método devuelve un hash de los atributos con sus valores originales y changes devuelve un hash de los atributos con sus valores originales y nuevos (en una matriz).

Puede comprobar APIDock para qué versiones soportaban estos métodos.

Http://apidock.com/rails/ActiveModel/Dirty

 48
Author: campeterson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-26 21:22:16

ActiveModel::Dirty no funcionó para mí porque el @model.update_attributes() ocultó los cambios. Así es como detecté los cambios en un método update en un controlador:

def update
  @model = Model.find(params[:id])
  detect_changes

  if @model.update_attributes(params[:model])
    do_stuff if attr_changed?
  end
end

private

def detect_changes
  @changed = []
  @changed << :attr if @model.attr != params[:model][:attr]
end

def attr_changed?
  @changed.include :attr
end

Si usted está tratando de detectar una gran cantidad de cambios de atributos que podría conseguir desordenado sin embargo. Probablemente no debería hacer esto en un controlador, pero meh.

 13
Author: hamstar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-04 21:56:52

Las respuestas anteriores son mejores, pero sin embargo para el conocimiento tenemos otro enfoque también, Permite cambiar el valor de la columna' catagory ' para un objeto (@design),

@design.changes.has_key?('catagory')

El.los cambios devolverán un hash con clave como nombre de columna y valores como una matriz con dos valores [old_value, new_value] para cada columna. Por ejemplo, catagory para arriba se cambia de ' ABC 'a' XYZ ' de @design,

@design.changes   # => {} 
@design.catagory = 'XYZ'
@design.changes # => { 'catagory' => ['ABC', 'XYZ'] }

For references change in ROR

 1
Author: shubham mishra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-17 11:47:16

Para rails 5.1 + callbacks

Para mejorar este post y completar otras respuestas

La primera respuesta quedará obsoleta para las devoluciones de llamada en las siguientes versiones de rails (después de la 5.1).
Así que la nueva forma de comprobar si un atributo ha cambiado es con saved_change_to_attribute?

Puedes hacer:

@user.saved_change_to_street1? # => true/false

Puedes ver más ejemplos aquí en este post blog

 1
Author: Lucas Andrade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-21 20:42:03