Schienen: update_attribute vs update_attributes

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

Beide aktualisieren ein Objekt, ohne AR explizit anweisen zu müssen, es zu aktualisieren.

Rails API sagt:

für update_attribute

Aktualisiert ein einzelnes Attribut und speichert den Datensatz, ohne das normale Validierungsverfahren durchlaufen zu haben. Dies ist besonders nützlich für boolesche Flags in vorhandenen Datensätzen. Die reguläre update_attribute-Methode in Base wird durch diese ersetzt, wenn das Validierungsmodul eingemischt wird, was standardmäßig der Fall ist.

für update_attributes

Aktualisiert alle Attribute des übergebenen Hash und speichert den Datensatz. Wenn das Objekt ungültig ist, schlägt das Speichern fehl und false wird zurückgegeben.

Wenn ich das Objekt nicht validieren lassen möchte, sollte ich update_attribute verwenden. Was passiert, wenn ich dieses Update auf einem before_save habe, wird es überlaufen?

Meine Frage ist, ob update_attribute auch das vor dem Speichern oder nur die Validierung umgeht.

Was ist die richtige Syntax, um einen Hash an update_attributes zu übergeben? Schauen Sie sich mein Beispiel oben an.

thenengah
quelle
Warum möchten Sie eine update_attributeAnweisung in einen before_saveRückruf einfügen? Ich kann mir keinen guten Grund dafür vorstellen.
Daniel Pietzsch
1
Ich habe Objekte, die basierend auf der Menge des aktualisierten Objekts aktualisiert werden müssen. Was ist besser?
Thenengah
Habe ich recht, dass die Objekte, die Sie aktualisieren müssen, Attribute des Objekts sind, das Sie speichern? Wenn ja, können Sie sie einfach festlegen, und sie werden zusammen mit dem ohnehin gespeicherten Objekt aktualisiert (da sie innerhalb eines before_saveRückrufs festgelegt werden). Fe anstelle von update_attribute(:discount, 0.1) if amount > 100dir könnte tun discount = 0.1 if amount > 100. update_attributeruft savedas Objekt auf, was in diesem Fall nicht erforderlich ist, da sich die Anweisung in einem before_saveRückruf befindet und trotzdem gespeichert wird. Ich hoffe das ergibt Sinn.
Daniel Pietzsch
Ja und nein. Der Status der Objekte, auf die Sie sich beziehen, hängt jedoch von anderen Bedingungen ab, die vor dem Speichern nicht verarbeitet werden können.
Thenengah
3
Als Hinweis, diese Methoden überspringen die Validierung, führen aber weiterhin Rückrufe durch, wie after_save ...
rogerdpack

Antworten:

328

Bitte beziehen Sie sich auf update_attribute. Wenn Sie auf Quelle anzeigen klicken, erhalten Sie den folgenden Code

      # 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

und jetzt beziehen Sie update_attributessich auf den Code, den Sie erhalten

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

Der Unterschied zwischen zwei ist update_attributeVerwendungen, save(false)während update_attributesVerwendungen saveoder Sie können sagen save(true).

Entschuldigung für die lange Beschreibung, aber was ich sagen möchte, ist wichtig. save(perform_validation = true)Wenn perform_validationfalsch umgeht sie alle (überspringt wird das richtige Wort sein) Validierungen mit zugehörigen save.

Für die zweite Frage

Was ist die richtige Syntax, um einen Hash an update_attributes zu übergeben? Schauen Sie sich mein Beispiel oben an.

Ihr Beispiel ist richtig.

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

oder

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

oder wenn Sie alle Felder Daten & Name in einem Hash erhalten, sagen Sie params[:user]hier nur verwenden

Object.update_attributes(params[:user])
Salil
quelle
7
Ihre Aussage zu Rückrufen ist zumindest in falsch Rails 3. In den Kommentaren in der Quelle heißt es sehr deutlich, dass "Rückrufe aufgerufen werden".
Batkins
Ich stimme dem zu, was @Batkins sagt
Raf
3
@ Batkins noch Validierungen werden nicht ausgeführt - das ist der wichtigste Teil :)
Tigraine
1
Die obigen Links sind zumindest ab Rails 5.1 nicht mehr korrekt . Diese Methoden wurden nach ActiveRecord :: Persistence verschoben. Sie finden die aktualisierten Informationen hier: update attribute und hier update_attributes Hinweis: update_attributesist jetzt ein Alias ​​fürupdate
tgf
74

Tipp: Wirdupdate_attribute in Rails 4 über Commit a7f4b0a1 nicht mehr unterstützt . Es wird update_attributezugunsten von entfernt update_column.

Matt
quelle
45
Dies ist nicht mehr wahr; Die Methode wurde erneut hinzugefügt. Siehe github.com/rails/rails/pull/6738#issuecomment-39584005
Dennis
20
update_attributeValidierung überspringt, aber respektieren Rückrufe, update_columnwerden sowohl die Validierung und Rückrufe und pflegen Updates überspringen :updated_at, updateist die normale Funktion , die beiden Rückrufe und Validierung respektieren
Mohammad AbuShady
2
werden sie sich schon entscheiden. reset_column, update_column ebenfalls veraltet.
Ahnbizcad
2
update_columnist nicht veraltet, wird aber update_columns(name: value)bevorzugt. reset_columnwurde entfernt.
Onebree
15

update_attribute

Diese Methode aktualisiert ein einzelnes Objektattribut, ohne die modellbasierte Validierung aufzurufen.

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

update_attributes

Diese Methode aktualisiert mehrere Attribute eines einzelnen Objekts und besteht auch die modellbasierte Validierung.

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

Ich hoffe, diese Antwort klärt, wann welche Methode der aktiven Aufzeichnung verwendet werden soll.

Balachandar1887229
quelle
12

Erwähnenswert ist auch, dass update_attributedas gewünschte zu aktualisierende Attribut nicht mit einer weißen Liste versehen werden muss attr_accessible, um es zu aktualisieren, im Gegensatz zur Massenzuweisungsmethode, bei update_attributesder nur attr_accessiblebestimmte Attribute aktualisiert werden.

Kibet Yegon
quelle
8

update_attributeaktualisiert einfach nur ein Attribut eines Modells, aber wir können mehrere Attribute in der update_attributesMethode übergeben.

Beispiel:

user = User.last

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

Es besteht die Validierung

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

Es wird nicht aktualisiert, wenn die Validierung fehlschlägt.

Shoaib Malik
quelle
Sehr gut erklärt. Vielen Dank!
Diego Somar
6

Tolle Antworten. Beachten Sie, dass Sie für Ruby 1.9 und höher die neue Hash-Syntax für update_attributes verwenden können (und sollten).

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

Möglicherweise möchten Sie diesen Blog-Beitrag besuchen, in dem alle Möglichkeiten zum Zuweisen eines Attributs oder eines Aktualisierungsdatensatzes (aktualisiert auf Rails 4) update_attribute, update, update_column, update_columns etc. erläutert werden . Http://www.davidverhasselt.com/set-attributes-in-activerecord/ . Beispielsweise unterscheidet es sich in Aspekten wie dem Ausführen von Validierungen, dem Berühren des aktualisierten_at des Objekts oder dem Auslösen von Rückrufen.

Als Antwort auf die Frage des OP update_attributewerden Rückrufe nicht umgangen.

Adamliesko
quelle
Ja sicher, ich habe die Antwort geändert. Danke für die Rückmeldung.
Adamliesko
4

update_attributeund update_attributessind ähnlich, aber mit einem großen Unterschied: update_attribute führt keine Validierungen durch.

Ebenfalls:

  • update_attributewird verwendet, um den Datensatz mit einem einzelnen Attribut zu aktualisieren .

    Model.update_attribute(:column_name, column_value1)
  • update_attributeswird verwendet, um den Datensatz mit mehreren Attributen zu aktualisieren .

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

Diese beiden Methoden sind aufgrund ihrer ähnlichen Namen und Werke sehr leicht zu verwechseln. Daher update_attributewird zugunsten von entfernt update_column.

Nun, in Rails4 können Sie verwenden , Model.update_column(:column_name, column_value)am Ort derModel.update_attribute(:column_name, column_value)

Klicken Sie hier , um weitere Informationen zu erhalten update_column.

uma
quelle
4

Um Ihre Frage zu beantworten, update_attributeüberspringen Sie vor dem Speichern "Validierungen", aber es werden immer noch andere Rückrufe wie ausgeführtafter_save usw. ausgeführt. Wenn Sie also wirklich "nur die Spalte aktualisieren und eine AR-Cruft überspringen" möchten, müssen Sie (anscheinend) verwenden.

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

Rogerdpack
quelle
2

Kürzlich bin ich auf ein update_attributevs. update_attributesund Validierungsproblem gestoßen, also ähnliche Namen, so unterschiedliches Verhalten, so verwirrend.

Um die Hash- update_attributeValidierung zu übergeben und die Validierung zu umgehen, haben Sie folgende Möglichkeiten:

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

Ich denke, Ihre Frage ist, ob ein update_attribute in einem before_save zu einer Endlosschleife führt (von update_attribute-Aufrufen in before_save-Rückrufen, die ursprünglich durch einen update_attribute-Aufruf ausgelöst wurden).

Ich bin mir ziemlich sicher, dass es den before_save-Rückruf umgeht, da es den Datensatz nicht wirklich speichert. Sie können einen Datensatz auch speichern, ohne Validierungen mit auszulösen

Model.save false

concept47
quelle