Rails: update_attribute vs update_attributes

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

Les deux mettront à jour un objet sans avoir à dire explicitement à AR de mettre à jour.

L'API Rails dit:

pour update_attribute

Met à jour un seul attribut et sauvegarde l'enregistrement sans passer par la procédure de validation normale. Ceci est particulièrement utile pour les indicateurs booléens sur les enregistrements existants. La méthode régulière update_attribute dans Base est remplacée par ceci lorsque le module de validations est mélangé, ce qui est par défaut.

pour update_attributes

Met à jour tous les attributs du hachage transmis et enregistre l'enregistrement. Si l'objet n'est pas valide, l'enregistrement échouera et false sera renvoyé.

Donc, si je ne veux pas faire valider l'objet, je dois utiliser update_attribute. Que se passe-t-il si j'ai cette mise à jour sur un before_save?

Ma question est la suivante: update_attribute contourne également la sauvegarde avant ou juste la validation.

En outre, quelle est la syntaxe correcte pour passer un hachage à update_attributes ... consultez mon exemple en haut.

thenengah
la source
Pourquoi voulez-vous mettre une update_attributedéclaration dans un before_saverappel? Je ne vois pas de bonne raison à cela.
Daniel Pietzsch
1
J'ai des objets qui doivent être mis à jour en fonction du montant de l'objet mis à jour. Quelle est la meilleure façon?
thenengah
Ai-je raison de dire que les objets que vous devez mettre à jour sont des attributs de l'objet que vous enregistrez? Si oui, vous pouvez simplement les définir et ils seront mis à jour avec l'objet qui est enregistré de toute façon (car ils sont définis dans un before_saverappel). Fe au lieu de update_attribute(:discount, 0.1) if amount > 100vous pourrait faire discount = 0.1 if amount > 100. update_attributeappelle savel'objet, ce qui n'est pas nécessaire dans ce cas, car l'instruction se trouve dans un before_saverappel et sera quand même enregistrée. J'espère que cela à du sens.
Daniel Pietzsch
Oui et non. Cependant, le statut des objets auxquels vous faites référence dépend d'autres conditions qui ne peuvent pas être traitées avant l'enregistrement.
thenengah
3
comme note, ces méthodes ignorent la validation mais effectueront toujours des rappels, comme after_save ...
rogerdpack

Réponses:

328

Veuillez vous référer à update_attribute. En cliquant sur show source, vous obtiendrez le code suivant

      # 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

et maintenant référez update_attributes- vous et regardez son code que vous obtenez

      # 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 différence entre deux est les update_attributeutilisations save(false)alors que les update_attributesutilisations saveou vous pouvez dire save(true).

Désolé pour la longue description mais ce que je veux dire est important. save(perform_validation = true), si perform_validationest faux, il contourne (les sauts seront le mot approprié) toutes les validations associées save.

Pour la deuxième question

En outre, quelle est la syntaxe correcte pour passer un hachage à update_attributes ... consultez mon exemple en haut.

Votre exemple est correct.

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

ou

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

ou si vous obtenez tous les champs données et nom dans un hachage, dites params[:user]ici, utilisez simplement

Object.update_attributes(params[:user])
Salil
la source
7
Votre déclaration sur les rappels est incorrecte, du moins dans Rails 3. Il est dit très clairement dans les commentaires de la source que "les rappels sont invoqués".
Batkins
J'appuie ce que @Batkins dit
Raf
3
@Batkins, les validations ne sont toujours pas exécutées - c'est la partie la plus importante :)
Tigraine
1
Les liens ci-dessus ne sont plus précis au moins depuis Rails 5.1 . Ces méthodes ont été déplacées vers ActiveRecord :: Persistence. Vous pouvez trouver les informations mises à jour ici: attribut de mise à jour et ici update_attributes Remarque: update_attributesest maintenant un alias pourupdate
tgf
74

Astuce: update_attribute est obsolète dans Rails 4 via Commit a7f4b0a1 . Il supprime update_attributeen faveur de update_column.

Mat
la source
45
Ce n'est plus vrai; la méthode a été rajoutée. Voir github.com/rails/rails/pull/6738#issuecomment-39584005
Dennis
20
update_attributeignore la validation, mais respecte les rappels, update_columnignorera la validation et les rappels et ne mettra pas à jour :updated_at, updateest la fonction normale qui respectera à la fois les rappels et la validation
Mohammad AbuShady
2
Vont-ils déjà se décider? reset_column, update_column également déconseillé.
ahnbizcad
2
update_columnn'est pas déconseillé, mais update_columns(name: value)est favorisé. reset_columna été retiré.
onebree
15

update_attribute

Cette méthode met à jour un seul attribut d'objet sans invoquer la validation basée sur un modèle.

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

update_attributes

Cette méthode met à jour plusieurs attributs d'un seul objet et passe également la validation basée sur le modèle.

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

J'espère que cette réponse éclaircira quand utiliser quelle méthode d'enregistrement actif.

Balachandar1887229
la source
12

Il convient également de noter qu'avec update_attribute, l'attribut à mettre à jour n'a pas besoin d'être mis en liste blanche avec attr_accessiblepour le mettre à jour, contrairement à la méthode d'affectation en masse update_attributesqui ne mettra à jour attr_accessibleque les attributs spécifiés.

Kibet Yegon
la source
8

update_attributemet simplement à jour un seul attribut d'un modèle, mais nous pouvons passer plusieurs attributs dans la update_attributesméthode.

Exemple:

user = User.last

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

Il passe la validation

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

il ne se met pas à jour si la validation échoue.

Shoaib Malik
la source
Très bien expliqué. Merci!
Diego Somar
6

Excellentes réponses. notez que comme pour ruby ​​1.9 et supérieur, vous pouvez (et je pense que vous devriez) utiliser la nouvelle syntaxe de hachage pour update_attributes:

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

Vous pourriez être intéressé à visiter ce billet de blog concernant toutes les façons possibles d'attribuer un attribut ou un enregistrement de mise à jour (mis à jour vers Rails 4) update_attribute, update, update_column, update_columns etc. http://www.davidverhasselt.com/set-attributes-in-activerecord/ . Par exemple, il diffère par des aspects tels que l'exécution de validations, le fait de toucher l'objet updated_at ou le déclenchement de rappels.

Comme une réponse à la question du PO update_attributene passe pas par des rappels.

adamliesko
la source
Oui bien sûr, j'ai modifié la réponse. Merci pour les commentaires.
adamliesko
4

update_attributeet update_attributessont similaires, mais avec une grande différence: update_attribute ne lance pas les validations.

Aussi:

  • update_attributeest utilisé pour mettre à jour l'enregistrement avec un seul attribut.

    Model.update_attribute(:column_name, column_value1)
  • update_attributesest utilisé pour mettre à jour l'enregistrement avec plusieurs attributs.

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

Ces deux méthodes sont vraiment faciles à confondre étant donné leurs noms et travaux similaires. Par conséquent, update_attributeest supprimé en faveur de update_column.

Maintenant, dans Rails4, vous pouvez utiliser Model.update_column(:column_name, column_value)à l'endroit deModel.update_attribute(:column_name, column_value)

Cliquez ici pour obtenir plus d'informations sur update_column.

uma
la source
4

Pour répondre à votre question, update_attributeignore les "validations" de pré-sauvegarde, mais il exécute toujours tous les autres rappels comme after_saveetc.

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

rogerdpack
la source
2

Récemment , je suis tombé sur update_attributecontre update_attributeset problème de validation, si des noms similaires, si différents comportements, confusion.

Pour passer le hachage update_attributeet contourner la validation, vous pouvez faire:

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

Je pense que votre question est de savoir si avoir un update_attribute dans un before_save conduira à une boucle sans fin (des appels update_attribute dans les rappels before_save, initialement déclenchés par un appel update_attribute)

Je suis presque sûr qu'il contourne le rappel before_save car il ne sauvegarde pas réellement l'enregistrement. Vous pouvez également sauvegarder un enregistrement sans déclencher de validation en utilisant

Model.save false

concept47
la source