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.


¿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])

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.


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.


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.


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.


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")

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.


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.


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


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)

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.