Rails: update_attribute vs update_attributes

255
Object.update_attribute(:only_one_field, "Some Value")
Object.update_attributes(:field1 => "value", :field2 => "value2", :field3 => "value3")

Ambos actualizarán un objeto sin tener que decirle explícitamente a AR que actualice.

Rails API dice:

para update_attribute

Actualiza un solo atributo y guarda el registro sin pasar por el procedimiento normal de validación. Esto es especialmente útil para banderas booleanas en registros existentes. El método regular update_attribute en Base se reemplaza por esto cuando se mezcla el módulo de validaciones, que es el predeterminado.

para update_attributes

Actualiza todos los atributos del hash pasado y guarda el registro. Si el objeto no es válido, el guardado fallará y se devolverá falso.

Entonces, si no quiero validar el objeto, debería usar update_attribute. ¿Qué pasa si tengo esta actualización en un before_save, se apilará?

Mi pregunta es ¿update_attribute también omite el guardado anterior o solo la validación?

Además, ¿cuál es la sintaxis correcta para pasar un hash a update_attributes ... mira mi ejemplo en la parte superior.

thenengah
fuente
¿Por qué quieres poner una update_attributedeclaración dentro de una before_savedevolución de llamada? No puedo pensar en una buena razón para esto.
Daniel Pietzsch
1
Tengo objetos que deben actualizarse en función de la cantidad del objeto actualizado. ¿Cuál es la mejor manera?
thenengah
¿Estoy en lo cierto, que los objetos que necesita actualizar son atributos del objeto que está guardando? En caso afirmativo, puede configurarlos y se actualizarán junto con el objeto que se guarda de todos modos (porque se configuran dentro de una before_savedevolución de llamada). Fe en lugar de update_attribute(:discount, 0.1) if amount > 100ti podría hacer discount = 0.1 if amount > 100. update_attributeinvoca saveel objeto, lo cual es innecesario en este caso, ya que la declaración está dentro de una before_savedevolución de llamada y se guardará de todos modos. Espero que tenga sentido.
Daniel Pietzsch
Si y no. Sin embargo, el estado de los objetos a los que se refiere depende de otras condiciones que no se pueden procesar antes de guardar.
thenengah
3
como nota, estos métodos omiten la validación pero aún realizarán devoluciones de llamada, como after_save ...
rogerdpack

Respuestas:

328

Por favor refiérase a update_attribute. Al hacer clic en mostrar fuente, obtendrá el siguiente código

      # File vendor/rails/activerecord/lib/active_record/base.rb, line 2614
2614:       def update_attribute(name, value)
2615:         send(name.to_s + '=', value)
2616:         save(false)
2617:       end

y ahora update_attributesconsulta y mira su código que obtienes

      # File vendor/rails/activerecord/lib/active_record/base.rb, line 2621
2621:       def update_attributes(attributes)
2622:         self.attributes = attributes
2623:         save
2624:       end

la diferencia entre dos es update_attributeusos, save(false)mientras que update_attributesusos saveo se puede decir save(true).

Perdón por la larga descripción, pero lo que quiero decir es importante. save(perform_validation = true), si perform_validationes falso, omite (omitir será la palabra adecuada) todas las validaciones asociadas con save.

Para la segunda pregunta

Además, ¿cuál es la sintaxis correcta para pasar un hash a update_attributes ... mira mi ejemplo en la parte superior.

Tu ejemplo es correcto.

Object.update_attributes(:field1 => "value", :field2 => "value2", :field3 => "value3")

o

Object.update_attributes :field1 => "value", :field2 => "value2", :field3 => "value3"

o si obtiene todos los datos y nombre de los campos en un hash, diga params[:user]aquí, use solo

Object.update_attributes(params[:user])
Salil
fuente
77
Su declaración sobre devoluciones de llamada es incorrecta, al menos en Rails 3. Dice muy claramente en los comentarios en la fuente que "se invocan devoluciones de llamada".
Batkins
Secundo lo que dice @Batkins
Raf
3
@Batkins todavía no se ejecutan validaciones, esa es la parte más importante :)
Tigraine
1
Los enlaces anteriores ya no son precisos al menos a partir de Rails 5.1 . Estos métodos se movieron a ActiveRecord :: Persistence. Puede encontrar la información actualizada aquí: atributo de actualización y aquí atributos_actualización Nota: update_attributesahora es un alias paraupdate
tgf
74

Sugerencia: update_attribute está en desuso en Rails 4 a través de Commit a7f4b0a1 . Se elimina update_attributea favor de update_column.

Mate
fuente
45
Esto ya no es verdad; El método ha sido re-agregado. Ver github.com/rails/rails/pull/6738#issuecomment-39584005
Dennis
20
update_attributeomite la validación, pero respeta las devoluciones de llamada, update_columnomitirá tanto la validación como las devoluciones de llamada y no se actualizará :updated_at, updatees la función normal que respetará tanto las devoluciones de llamada como la validación
Mohammad AbuShady
2
¿Ya van a decidirse? reset_column, update_column también en desuso.
ahnbizcad
2
update_columnno está en desuso, pero update_columns(name: value)es favorecido. reset_columnha sido removido.
onebree
15

atributo_actualización

Este método actualiza el atributo único del objeto sin invocar la validación basada en el modelo.

obj = Model.find_by_id(params[:id])
obj.update_attribute :language, java

atributos_actualización

Este método actualiza múltiples atributos de un solo objeto y también pasa la validación basada en el modelo.

attributes = {:name => BalaChandar”, :age => 23}
obj = Model.find_by_id(params[:id])
obj.update_attributes(attributes)

Espero que esta respuesta aclare cuándo usar qué método de registro activo.

Balachandar1887229
fuente
12

También vale la pena señalar que con update_attribute, el atributo deseado que se actualizará no necesita estar en una lista blanca attr_accessiblepara actualizarlo en lugar del método de asignación masiva update_attributesque solo actualizará attr_accessiblelos atributos especificados.

Kibet Yegon
fuente
8

update_attributesimplemente actualiza solo un atributo de un modelo, pero podemos pasar múltiples atributos en el update_attributesmétodo.

Ejemplo:

user = User.last

#update_attribute
user.update_attribute(:status, "active")

Pasa la validación

#update_attributes
user.update_attributes(first_name: 'update name', status: "active")

no se actualiza si falla la validación.

Shoaib Malik
fuente
Muy bien explicado. ¡Gracias!
Diego Somar
6

Grandes respuestas tenga en cuenta que en cuanto a ruby ​​1.9 y superior, podría (y creo que debería) usar la nueva sintaxis hash para update_attributes:

Model.update_attributes(column1: "data", column2: "data")
Ziv Galili
fuente
6

Es posible que le interese visitar esta publicación de blog sobre todas las formas posibles de asignar un atributo o actualizar el registro (actualizado a Rails 4) update_attribute, update, update_column, update_columns etc. http://www.davidverhasselt.com/set-attributes-in-activerecord/ . Por ejemplo, difiere en aspectos como la ejecución de validaciones, tocar el objeto updated_at del objeto o activar devoluciones de llamada.

Como respuesta a la pregunta del OP, update_attributeno pasa las devoluciones de llamada.

adamliesko
fuente
Sí claro, modifiqué la respuesta. Gracias por la respuesta.
adamliesko
4

update_attributey update_attributesson similares, pero con una gran diferencia: update_attribute no ejecuta validaciones.

También:

  • update_attributese usa para actualizar el registro con un solo atributo.

    Model.update_attribute(:column_name, column_value1)
  • update_attributesse utiliza para actualizar registros con múltiples atributos.

    Model.update_attributes(:column_name1 => column_value1, :column_name2 => column_value2, ...)

Estos dos métodos son realmente fáciles de confundir dados sus nombres y trabajos similares. Por lo tanto, update_attributese está eliminando a favor de update_column.

Ahora, en Rails4 puedes usarlo Model.update_column(:column_name, column_value)en el lugar deModel.update_attribute(:column_name, column_value)

Haga clic aquí para obtener más información sobre update_column.

uma
fuente
4

Para responder a su pregunta, update_attributeomite las "validaciones" previas al guardado, pero aún ejecuta otras devoluciones de llamada como after_saveetc. Así que si realmente desea "simplemente actualizar la columna y omitir cualquier desmoronamiento AR", entonces debe usar (aparentemente)

Model.update_all(...)ver https://stackoverflow.com/a/7243777/32453

rogerdpack
fuente
2

Recientemente me encontré con el problema de update_attributevs update_attributesy validación, nombres muy similares, comportamiento tan diferente, tan confuso.

Para pasar el hash update_attributey omitir la validación, puede hacer:

object = Object.new
object.attributes = {
  field1: 'value',
  field2: 'value2',
  field3: 'value3'
}
object.save!(validate: false)
Wojciech Bednarski
fuente
1

Creo que su pregunta es si tener un atributo update_attribute en before_save conducirá a un bucle sin fin (de llamadas update_attribute en devoluciones de llamada before_save, originalmente activadas por una llamada update_attribute)

Estoy bastante seguro de que omite la devolución de llamada before_save ya que en realidad no guarda el registro. También puede guardar un registro sin activar validaciones utilizando

Model.save false

concepto47
fuente