Rails update_attributes senza salvare?


386

Esiste un'alternativa a update_attributes che non salva il record?

Quindi potrei fare qualcosa del tipo:

@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

A proposito, lo so che posso @car.model = 'Sierra', ma voglio aggiornarli tutti su una riga.


cosa intendi con "non salvare il record"?
Anatoly,

update_attributes salva il modello nel DB. Mi chiedo se esiste un metodo simile che non lo fa.
tybro0103,

3
attribuisce metodo non distruttivo. Vedi l' API per i dettagli
Anatoly,

3
È possibile utilizzare update_column (nome, valore) Aggiorna un singolo attributo di un oggetto, senza chiamare save. 1. La convalida viene ignorata. 2. I callback vengono saltati. 3. La colonna updated_at / updated_on non viene aggiornata se tale colonna è disponibile. apidock.com/rails/ActiveRecord/Persistence/update_column
Antoine

10
Per 3.1+, utilizzare assign_attributes apidock.com/rails/ActiveRecord/Base/assign_attributes
elado,

Risposte:


597

Credo che quello che stai cercando sia assign_attributes.

È praticamente lo stesso di update_attributes ma non salva il record:

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

Il tuo esempio è un po 'fuorviante poiché non hai incollato questa linea dal modello attr_accessible :is_admin, :as => :admin:;)
Robin

@Robin O semplicemente: attr_protected :is_admin. Oppure: attr_accessible :nameIl punto è che in questo esempio: is_admin è protetto. Dovrei anche notare che il tentativo di assegnare in massa un attributo protetto con .assign_attributeseffettivamente solleva un ActiveModel::MassAssignmentSecurity::Error, anche se questo non è mostrato nell'esempio.
Ajedi32,

Sì, ma la mia linea proviene dal documento a cui sei collegato. Sto solo dicendo che avresti dovuto copiare / incollare l'intero esempio. Ma sì, puoi solo dire che è protetto.
Robin,

@Robin Aggiornerò l'esempio per essere un po 'più specifico. Anche l'esempio nei documenti è un po 'fuorviante, in quanto non menziona il fatto che user.assign_attributes({ :name => 'Josh', :is_admin => true })genera un messaggio di errore e in realtà non imposta la proprietà del nome dell'utente.
Ajedi32,

7
assegnare_attributes è disponibile da Rails 3.1 in poi, quindi non puoi usarlo se stai ancora eseguendo una vecchia versione di Rails.
Haegin,

174

Puoi usare assign_attributesoattributes= (sono uguali)

Foglio informativo sui metodi di aggiornamento (per Rails 6):

  • update= assign_attributes+save
  • attributes= = alias di assign_attributes
  • update_attributes = deprecato, alias di update

Fonte:
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

Un altro cheat sheet:
http://www.davidverhasselt.com/set-attributes-in-activerecord/#cheat-sheet


1
Chiaro e breve. Grazie.
freemanoid,

1
in caso di .attributes = val, se il tuo modello ha_one e accetta_nested_attributes_ per un altro modello, passando that_model_attributes (senza ID) eliminerai il modello has_one esistente, anche se non hai persistito (es. salvataggio). Ma assegnare_attributes non si comporta così.
ClassyPimp

65

È possibile utilizzare il metodo "attributi":

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

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

attributi = (new_attributes, guard_protected_attributes = true) Consente di impostare tutti gli attributi contemporaneamente passando un hash con le chiavi che corrispondono ai nomi degli attributi (che corrisponde nuovamente ai nomi delle colonne).

Se guard_protected_attributes è true (impostazione predefinita), gli attributi sensibili possono essere protetti da questa forma di assegnazione di massa utilizzando la macro attr_protected. Oppure puoi in alternativa specificare a quali attributi è possibile accedere con la macro attr_accessible. Quindi non sarà possibile assegnare in massa tutti gli attributi non inclusi.

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

7

Per l'assegnazione di massa di valori a un modello ActiveRecord senza salvare, utilizzare i metodi assign_attributeso attributes=. Questi metodi sono disponibili in Rails 3 e versioni successive. Tuttavia, ci sono piccole differenze e aspetti da considerare relativi alla versione.

Entrambi i metodi seguono questo utilizzo:

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

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

Si noti che nessuno dei due metodi eseguirà convalide o eseguirà callback; i callback e la validazione avverranno quandosave viene chiamato.

Rotaie 3

attributes=differisce leggermente da assign_attributesin Rails 3. attributes=verificherà che l'argomento passato ad esso sia un hash e ritorni immediatamente in caso contrario; assign_attributesnon ha tale controllo hash. Consultare la documentazione dell'API di assegnazione degli attributi ActiveRecord perattributes= .

Il seguente codice non valido fallirà silenziosamente semplicemente ritornando senza impostare gli attributi:

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

attributes= si comporteranno silenziosamente come se gli incarichi fossero stati eseguiti con successo, quando in realtà non lo erano.

Questo codice non valido genererà un'eccezione quando assign_attributestenta di stringere le chiavi hash dell'array che la racchiude:

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

assign_attributesgenererà NoMethodErrorun'eccezione per stringify_keys, indicando che il primo argomento non è un hash. L'eccezione in sé non è molto istruttiva sulla causa reale, ma il fatto che si verifichi un'eccezione è molto importante.

L'unica differenza tra questi casi è il metodo utilizzato per l'assegnazione di massa: attributes=riesce silenziosamente e assign_attributesgenera un'eccezione per informare che si è verificato un errore.

Questi esempi possono sembrare inventati e sono in una certa misura, ma questo tipo di errore può facilmente verificarsi durante la conversione di dati da un'API o anche solo usando una serie di trasformazione dei dati e dimenticando Hash[]i risultati del finale .map. Mantieni alcune righe del codice 50 sopra e 3 funzioni rimosse dall'assegnazione degli attributi e hai una ricetta per il fallimento.

La lezione con Rails 3 è questa: usa sempreassign_attributes invece diattributes= .

Rotaie 4

In Rails 4, attributes=è semplicemente un alias di assign_attributes. Consultare la documentazione dell'API di assegnazione degli attributi ActiveRecord perattributes= .

Con Rails 4, entrambi i metodi possono essere usati in modo intercambiabile. Il mancato passaggio di un hash come primo argomento comporterà un'eccezione molto utile:ArgumentError: When assigning attributes, you must pass a hash as an argument.

Validazioni

Se stai preparando degli incarichi di volo in preparazione di un save, potresti essere interessato a convalidare anche prima del salvataggio. È possibile utilizzare i metodi valid?e invalid?per questo. Entrambi restituiscono valori booleani. valid?restituisce vero se il modello non salvato supera tutte le convalide o falso in caso contrario. invalid?è semplicemente l'inverso divalid?

valid? può essere usato in questo modo:

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

Ciò ti darà la possibilità di gestire eventuali problemi di convalida prima di chiamare save.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.