Rails update_attributes ohne speichern?

386

Gibt es eine Alternative zu update_attributes, bei der der Datensatz nicht gespeichert wird?

Also könnte ich so etwas machen wie:

@car = Car.new(:make => 'GMC')
#other processing
@car.update_attributes(:model => 'Sierra', :year => "2012", :looks => "Super Sexy, wanna make love to it")
#other processing
@car.save

Übrigens, ich weiß, dass ich es kann @car.model = 'Sierra', aber ich möchte sie alle in einer Zeile aktualisieren.

tybro0103
quelle
Was meinst du mit "nicht speichern"?
Anatoly
update_attributes speichert das Modell in der Datenbank. Ich frage mich, ob es eine ähnliche Methode gibt, die dies nicht tut.
tybro0103
3
Attribute zerstörungsfreie Methode. Siehe API für Details
Anatoly
3
Sie können update_column (Name, Wert) verwenden. Aktualisiert ein einzelnes Attribut eines Objekts, ohne save aufzurufen. 1. Die Validierung wird übersprungen. 2. Rückrufe werden übersprungen. 3. Die Spalte "aktualisiert_at / aktualisiert_on" wird nicht aktualisiert, wenn diese Spalte verfügbar ist. apidock.com/rails/ActiveRecord/Persistence/update_column
Antoine
10
Verwenden assign_attributes Sie
elado

Antworten:

597

Ich glaube, was Sie suchen, ist assign_attributes.

Es ist im Grunde dasselbe wie update_attributes, speichert jedoch nicht den Datensatz:

class User < ActiveRecord::Base
  attr_accessible :name
  attr_accessible :name, :is_admin, :as => :admin
end

user = User.new
user.assign_attributes({ :name => 'Josh', :is_admin => true }) # Raises an ActiveModel::MassAssignmentSecurity::Error
user.assign_attributes({ :name => 'Bob'})
user.name        # => "Bob"
user.is_admin?   # => false
user.new_record? # => true
Ajedi32
quelle
Ihr Beispiel ist ein wenig irreführend, da Sie diese Zeile aus dem Modell nicht eingefügt haben : attr_accessible :is_admin, :as => :admin;)
Robin
@Robin Oder einfach : attr_protected :is_admin. Oder: attr_accessible :nameDer Punkt ist, dass in diesem Beispiel: is_admin geschützt ist. Ich sollte auch beachten, dass der Versuch, ein geschütztes Attribut mit massenweise zuzuweisen, .assign_attributestatsächlich ein auslöst ActiveModel::MassAssignmentSecurity::Error, obwohl dies im Beispiel nicht gezeigt wird.
Ajedi32
Ja, aber meine Zeile stammt aus dem Dokument, mit dem Sie verlinkt haben. Ich sage nur, Sie hätten das ganze Beispiel kopieren / einfügen sollen. Aber ja, man kann nur sagen, dass es geschützt ist.
Robin
@Robin Ich werde das Beispiel etwas genauer aktualisieren. Das Beispiel in den Dokumenten ist auch etwas irreführend, da nicht erwähnt wird, dass user.assign_attributes({ :name => 'Josh', :is_admin => true })eine Fehlermeldung ausgegeben wird und die Namenseigenschaft des Benutzers nicht festgelegt wird.
Ajedi32
7
assign_attributes ist ab Rails 3.1 verfügbar, sodass Sie es nicht verwenden können, wenn Sie noch eine alte Version von Rails ausführen.
Haegin
174

Sie können assign_attributesoder verwendenattributes= (sie sind gleich)

Update Methoden Spickzettel (für Rails 6):

  • update= assign_attributes+save
  • attributes= = Alias ​​von assign_attributes
  • update_attributes = veraltet, Alias ​​von update

Quelle:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/persistence.rb
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_assignment .rb

Ein weiterer Spickzettel:
http://www.davidverhasselt.com/set-attributes-in-activerecord/#cheat-sheet

Yarin
quelle
1
Klar und kurz. Vielen Dank.
Freemanoid
1
Wenn bei .attributes = val Ihr Modell has_one hat und_nested_attributes_ für ein anderes Modell akzeptiert, wird durch Übergabe von that_model_attributes (ohne ID) das vorhandene has_one-Modell gelöscht, auch wenn Sie es nicht beibehalten haben (z. B. speichern). Aber assign_attributes verhält sich nicht so.
ClassyPimp
65

Sie können die Methode 'Attribute' verwenden:

@car.attributes = {:model => 'Sierra', :years => '1990', :looks => 'Sexy'}

Quelle: http://api.rubyonrails.org/classes/ActiveRecord/Base.html

Attribute = (new_attributes, guard_protected_attributes = true) Ermöglicht das aller Attribute durch Übergeben eines Hashs mit Schlüsseln, die mit den Attributnamen übereinstimmen (die wiederum mit den Spaltennamen übereinstimmen).

Wenn guard_protected_attributes true ist (Standardeinstellung), können vertrauliche Attribute mithilfe des attr_protected-Makros vor dieser Form der Massenzuweisung geschützt werden. Alternativ können Sie angeben, auf welche Attribute mit dem Makro attr_accessible zugegriffen werden kann. Dann dürfen nicht alle darin enthaltenen Attribute massenweise zugewiesen werden.

class User < ActiveRecord::Base
  attr_protected :is_admin
end

user = User.new
user.attributes = { :username => 'Phusion', :is_admin => true }
user.username   # => "Phusion"
user.is_admin?  # => false

user.send(:attributes=, { :username => 'Phusion', :is_admin => true }, false)
user.is_admin?  # => true
bruno077
quelle
7

Verwenden Sie für die Massenzuweisung von Werten zu einem ActiveRecord-Modell ohne Speichern entweder die Methoden assign_attributesoder attributes=. Diese Methoden sind in Rails 3 und neuer verfügbar. Es sind jedoch geringfügige Unterschiede und versionierungsbedingte Fallstricke zu beachten.

Beide Methoden folgen dieser Verwendung:

@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }

@user.attributes = { model: "Sierra", year: "2012", looks: "Sexy" }

Beachten Sie, dass keine der Methoden Überprüfungen durchführt oder Rückrufe ausführt. Rückrufe und Validierungen erfolgen, wennsave Aufruf.

Schienen 3

attributes=unterscheidet sich geringfügig von assign_attributesin Rails 3. attributes=prüft, ob das an ihn übergebene Argument ein Hash ist, und gibt sofort zurück, wenn dies nicht der Fall ist; assign_attributeshat keine solche Hash-Prüfung. Weitere Informationen finden Sie in der Dokumentation zur ActiveRecord-Attributzuweisungs-API fürattributes= .

Der folgende ungültige Code schlägt stillschweigend fehl, indem er einfach zurückgegeben wird, ohne die Attribute festzulegen:

@user.attributes = [ { model: "Sierra" }, { year: "2012" }, { looks: "Sexy" } ]

attributes= wird sich stillschweigend so verhalten, als ob die Zuweisungen erfolgreich durchgeführt wurden, obwohl dies wirklich nicht der Fall war.

Dieser ungültige Code assign_attributeslöst eine Ausnahme aus, wenn versucht wird, die Hash-Schlüssel des umschließenden Arrays zu stringifizieren:

@user.assign_attributes([ { model: "Sierra" }, { year: "2012" }, { looks: "Sexy" } ])

assign_attributeslöst eine NoMethodErrorAusnahme für aus stringify_keys, die angibt, dass das erste Argument kein Hash ist. Die Ausnahme selbst ist nicht sehr informativ über die tatsächliche Ursache, aber die Tatsache, dass eine Ausnahme auftritt, ist sehr wichtig.

Der einzige Unterschied zwischen diesen Fällen besteht in der Methode für die Massenzuweisung: Sie ist im attributes=Hintergrund erfolgreich und assign_attributeslöst eine Ausnahme aus, um zu informieren, dass ein Fehler aufgetreten ist.

Diese Beispiele scheinen erfunden zu sein, und sie sind bis zu einem gewissen Grad, aber diese Art von Fehler kann leicht auftreten, wenn Daten von einer API konvertiert werden oder wenn einfach nur eine Reihe von Datentransformationen verwendet und Hash[]die Ergebnisse des Finales vergessen werden .map. Behalten Sie den Code 50 Zeilen über und 3 Funktionen bei, die aus Ihrer Attributzuweisung entfernt wurden, und Sie haben ein Rezept für einen Fehler.

Die Lektion mit Rails 3 ist dies: immer verwendet assign_attributesstattattributes= .

Schienen 4

In Schienen 4, attributes= ist einfach ein Alias ​​zu assign_attributes. Weitere Informationen finden Sie in der Dokumentation zur ActiveRecord-Attributzuweisungs-API fürattributes= .

Bei Rails 4 kann jede Methode austauschbar verwendet werden. Wenn ein Hash nicht als erstes Argument übergeben wird, führt dies zu einer sehr hilfreichen Ausnahme:ArgumentError: When assigning attributes, you must pass a hash as an argument.

Validierungen

Wenn Sie in Vorbereitung auf a Aufgaben vor dem Flug ausführen, möchten saveSie möglicherweise auch vor dem Speichern validiert werden. Hierfür können Sie die Methoden valid?und invalid?verwenden. Beide geben boolesche Werte zurück. valid?Gibt true zurück, wenn das nicht gespeicherte Modell alle Überprüfungen besteht, oder false, wenn dies nicht der Fall ist. invalid?ist einfach das Gegenteil vonvalid?

valid? kann wie folgt verwendet werden:

@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }.valid?

Auf diese Weise können Sie Validierungsprobleme vor dem Anruf bearbeiten save.

Michael Gaskill
quelle