Rails 3 comprueba si el atributo ha cambiado

Necesita verificar 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 pedazo de código será REALMENTE largo. ¿Hay una manera más limpia?

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

 @user.street1_changed? # => true/false 

Así es como resolví el problema de verificar cambios en múltiples atributos.

 attrs = ["street1", "street2", "city", "state", "zipcode"] if (@user.changed & attrs).any? then do something.... end 

El método changed devuelve una matriz de los atributos modificados para ese objeto.

Both @user.changed y attrs son matrices, así que puedo obtener la intersección (ver ary & other ary método ary & other ary ). El resultado de la intersección es una matriz. Al llamar a any? en la matriz, me hago verdadero si hay al menos una intersección.

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

Puede verificar APIDock para qué versiones admiten estos métodos.

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

ActiveModel::Dirty no funcionó para mí porque @model.update_attributes() ocultó los cambios. Entonces, así es como detecté los cambios en un método de 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 

Sin embargo, si intentas detectar muchos cambios de atributos, podría ser complicado. Probablemente no debería hacer esto en un controlador, pero meh.

Las respuestas anteriores son mejores, pero aun así, para conocimiento, tenemos otra aproximación, permite cambiar el valor de la columna ‘catagory’ para un objeto (@design),

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

Los .changes devolverán un hash con clave como el nombre y los valores de la columna como una matriz con dos valores [old_value, new_value] para cada columna. Por ejemplo, la categoría de arriba se cambia de ‘ABC’ a ‘XYZ’ de @design,

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

Para referencias, cambio en ROR

Para carriles 5.1 + devoluciones de llamada

Para mejorar esta publicación y completar otras respuestas

La primera respuesta quedará obsoleta para las devoluciones de llamada en las siguientes versiones de Rails (después de 5.1).
¿Entonces la nueva forma de verificar si un atributo ha cambiado es con saved_change_to_attribute?

Tu puedes hacer:

 @user.saved_change_to_street1? # => true/false 

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