Rotaie: update_attribute vs update_attributes


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

Entrambi aggiorneranno un oggetto senza dover dire esplicitamente ad AR di aggiornarlo.

L'API di Rails dice:

per update_attribute

Aggiorna un singolo attributo e salva il record senza passare attraverso la normale procedura di convalida. Ciò è particolarmente utile per flag booleani su record esistenti. Il normale metodo update_attribute in Base viene sostituito con questo quando il modulo di convalida viene miscelato, che è per impostazione predefinita.

per update_attributes

Aggiorna tutti gli attributi dall'hash passato e salva il record. Se l'oggetto non è valido, il salvataggio fallirà e verrà restituito falso.

Quindi, se non voglio che l'oggetto sia validato, dovrei usare update_attribute. Cosa succede se ho questo aggiornamento su un before_save, impilerà overflow?

La mia domanda è che update_attribute ignora anche il salvataggio precedente o solo la convalida.

Inoltre, qual è la sintassi corretta per passare un hash a update_attributes ... dai un'occhiata al mio esempio in alto.


Perché vuoi inserire una update_attributedichiarazione all'interno di una before_saverichiamata? Non riesco a pensare a una buona ragione per questo.
Daniel Pietzsch,

1
Ho oggetti che devono essere aggiornati in base alla quantità dell'oggetto aggiornato. Qual è il modo migliore?
thenengah,

Ho ragione, gli oggetti che devi aggiornare sono attributi dell'oggetto che stai salvando? Se sì, allora puoi semplicemente impostarli e verranno aggiornati insieme all'oggetto che viene salvato comunque (perché sono impostati in un before_savecallback). Fe invece di update_attribute(:discount, 0.1) if amount > 100te potrebbe fare discount = 0.1 if amount > 100. update_attributechiama savel'oggetto, che in questo caso non è necessario, poiché l'istruzione si trova all'interno di un before_savecallback e verrà comunque salvata. Spero che abbia un senso.
Daniel Pietzsch,

Sì e no. Tuttavia, lo stato degli oggetti a cui si fa riferimento dipende da altre condizioni che non possono essere elaborate prima del salvataggio.
thenengah,

3
come nota, questi metodi saltano la convalida ma eseguiranno comunque callback, come after_save ...
rogerdpack

Risposte:


328

Si prega di fare riferimento a update_attribute. Cliccando su show source otterrai il seguente codice

      # 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

e ora update_attributesfai riferimento e guarda il suo codice che ottieni

      # 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 differenza tra due è update_attributeusi save(false)mentre update_attributesusi saveo puoi dire save(true).

Ci scusiamo per la lunga descrizione, ma quello che voglio dire è importante. save(perform_validation = true), se perform_validationè falso, ignora (salterà la parola corretta) tutte le convalide associate save.

Per la seconda domanda

Inoltre, qual è la sintassi corretta per passare un hash a update_attributes ... dai un'occhiata al mio esempio in alto.

Il tuo esempio è corretto.

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

o

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

o se ottieni tutti i dati dei campi e il nome in un hash, params[:user]usa qui solo

Object.update_attributes(params[:user])

7
La tua dichiarazione sui callback è errata, almeno in Rails 3. Dice chiaramente nei commenti nella fonte che "I callback sono invocati".
Batkins,

I secondi ciò che dice @Batkins
Raf

3
Le validazioni di @Batkins non vengono eseguite - questa è la parte più importante :)
Tigraine,

1
I link sopra non sono più precisi almeno a partire da Rails 5.1 . Questi metodi sono stati spostati in ActiveRecord :: Persistence. Puoi trovare le informazioni aggiornate qui: aggiorna l'attributo e qui update_attributes Nota: update_attributesora è un alias perupdate
tgf

74

Suggerimento: update_attribute viene deprecato in Rails 4 tramite Commit a7f4b0a1 . Rimuove update_attributea favore di update_column.


45
Questo non è più vero; il metodo è stato aggiunto di nuovo. Vedi github.com/rails/rails/pull/6738#issuecomment-39584005
Dennis

20
update_attributesalta la convalida, ma rispetta i callback, update_columnsalterà sia la validazione che i callback e non si aggiorna :updated_at, updateè la normale funzione che rispetterà sia i callback che la convalida
Mohammad AbuShady,

2
decideranno già? reset_column, anche update_column obsoleto.
ahnbizcad,

2
update_columnnon è deprecato, ma update_columns(name: value)è favorito. reset_columnè stato rimosso.
onebree

15

update_attribute

Questo metodo aggiorna l'attributo singolo dell'oggetto senza richiamare la convalida basata sul modello.

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

update_attributes

Questo metodo aggiorna l'attributo multiplo di un singolo oggetto e passa anche la convalida basata sul modello.

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

Spero che questa risposta chiarisca quando utilizzare quale metodo di registrazione attiva.


12

Vale anche la pena notare che con update_attribute, l'attributo desiderato da aggiornare non ha bisogno di essere elencato in bianco attr_accessibleper aggiornarlo rispetto al metodo di assegnazione di massa update_attributesche aggiornerà solo gli attr_accessibleattributi specificati.


8

update_attributeaggiorna semplicemente un solo attributo di un modello, ma possiamo passare più attributi nel update_attributesmetodo.

Esempio:

user = User.last

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

Passa la convalida

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

non si aggiorna se la validazione fallisce.


Molto ben spiegato. Grazie!
Diego Somar,

6

Grandi risposte. nota che per quanto riguarda ruby ​​1.9 e versioni successive potresti (e penso che dovrei) usare la nuova sintassi hash per update_attributes:

Model.update_attributes(column1: "data", column2: "data")

6

Potresti essere interessato a visitare questo post sul blog relativo a tutti i modi possibili per assegnare un attributo o aggiornare il record (aggiornato a Rails 4) update_attribute, update, update_column, update_columns etc. http://www.davidverhasselt.com/set-attributes-in-activerecord/ . Ad esempio, differisce in aspetti come l'esecuzione di convalide, il tocco di un oggetto_avviato o l'attivazione di richiamate.

Come risposta alla domanda del PO update_attributenon si superano i callback.


Sì certo, ho modificato la risposta. Grazie per il feedback.
adamliesko,

4

update_attributee update_attributessono simili, ma con una grande differenza: update_attribute non esegue convalide.

Anche:

  • update_attributeviene utilizzato per aggiornare il record con un singolo attributo.

    Model.update_attribute(:column_name, column_value1)
  • update_attributesviene utilizzato per aggiornare il record con più attributi.

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

Questi due metodi sono davvero facili da confondere dati i loro nomi e opere simili. Pertanto, update_attributeviene rimosso a favore di update_column.

Ora, in Rails4 puoi usare Model.update_column(:column_name, column_value)al posto diModel.update_attribute(:column_name, column_value)

Clicca qui per avere maggiori informazioni su update_column.


4

Per rispondere alla tua domanda, update_attributesalta pre-salvare "convalide" ma esegue comunque qualsiasi altro callback come after_saveecc. Quindi, se vuoi veramente "aggiorna la colonna e salta qualsiasi AR cruft" allora devi usare (apparentemente)

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


2

Di recente ho riscontrato un problema di convalida e update_attributevs. update_attributes, quindi nomi simili, comportamenti così diversi, così confusi.

Per passare l'hash update_attributee bypassare la convalida puoi fare:

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

1

Penso che la tua domanda sia se avere un update_attribute in un before_save porterà a un ciclo infinito (di chiamate update_attribute in callback before_save, originariamente innescate da una chiamata update_attribute)

Sono abbastanza sicuro che ignora il callback before_save poiché in realtà non salva il record. È inoltre possibile salvare un record senza attivare convalide utilizzando

Model.save false

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.