2011-02-03 9 views
38

Come posso ottenere questo risultato?Come aggiornare un singolo attributo senza toccare l'attributo updated_at?

cercato di creare 2 metodi, chiamati

def disable_timestamps 
    ActiveRecord::Base.record_timestamps = false 
end 

def enable_timestamps 
    ActiveRecord::Base.record_timestamps = true 
end 

e il metodo di aggiornamento stesso:

def increment_pagehit 
    update_attribute(:pagehit, pagehit+1) 
end 

timestamp accendere e spegnere utilizzando callback come:

before_update :disable_timestamps, :only => :increment_pagehit 
after_update :enable_timestamps, :only => :increment_pagehit 

ma non è aggiornando qualsiasi cosa, anche l'attributo desiderato (pagehit).

Qualche consiglio? Non voglio dover creare un altro tavolo solo per contare le pagehits.

+0

Provare a utilizzare 'update_attributes! (: Pagehit => pagehit + 1)' e vedere se si verificano errori. BTW, hai incollato 'def disable_timestamps' due volte per errore qui, o è lo stesso nel tuo codice? – Zabba

+0

Possibile duplicato di [C'è un modo per evitare di aggiornare automaticamente i campi di data e ora di Rails?] (Http://stackoverflow.com/questions/861448/is-there-a-way-to-avoid-automatically-updating-rails-timestamp -fields) –

risposta

12

Se tutto hai intenzione di fare è incrementare un contatore, userei il metodo increment_counter invece:

ModelName.increment_counter :pagehit, id 
+0

Voglio incrementare il contatore ma senza modificare il valore updated_at. –

+2

@ kleber-s; increment_counter non cambia aggiornato_at. – idlefingers

+0

Funziona, e c'è un nuovo modo in Rails 3. Una cosa che noto è che il contatore viene incrementato dopo la visualizzazione della pagina. – lulalala

85

In alternativa a update_attribute, In Rails 3.1+ è possibile utilizzare update_column.

update_attribute salta le convalide, ma toccherà updated_at ed eseguirà le richiamate.

update_column ignora convalide, non tocca updated_at e non esegue callback.

Pertanto, update_column è un'ottima scelta se non si desidera modificare updated_at e non è necessario richiamare.

Vedere http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html per ulteriori informazioni.

Si noti inoltre che update_column aggiornerà il valore dell'attributo nel modello in memoria e non verrà contrassegnato come sporco. Per esempio:

p = Person.new(:name => "Nathan") 
p.save 
p.update_column(:name, "Andrew") 
p.name == "Andrew" # True 
p.name_changed? # False 
+0

Bello! Grazie per l'info! ;) –

+2

L'equivalente mongoidale di 'update_column' è' set', come in 'person.set (: name, 'Andrew')'. [Mongoid Docs - Atomic Persistence] (http://mongoid.org/en/mongoid/docs/persistence.html#atomic) – colllin

2

Per evitare Monkeypatchingtroubles si potrebbe anche usare ModelName.update_all per questo scopo:

def increment_pagehit 
    self.class.update_all({ pagehit: pagehit+1 }, { id: id }) 
end 

Anche questo non tocchi il timestamp sul record.

2

non è una buona idea per fare questo:

self.class.update_all({ pagehit: pagehit+1 }, { id: id }) 

dovrebbe essere

self.class.update_all("pagehit = pagehit + 1", { id: id }) 

la ragione è che se due richieste sono parallele, sulla prima versione sia aggiornerà il pagehits con lo stesso numero, poiché utilizza il numero salvato nella memoria Ruby.La seconda opzione utilizza il server sql per aumentare il numero di 1, nel caso in cui due di queste query si presentino nello stesso momento, il server le elaborerà una dopo l'altra e finirà con il numero corretto di pagehits.

-1

Se la precisione non è poi così importante, e non si aspetta il codice per eseguire molte volte, si può provare a modificare le salvato nel valore del database updated_at, in questo modo:

u = User.first 
u.name = "Alex 2" # make some changes... 
u.updated_at = u.updated_at + 0.000001.second # alter updated_at 
u.save 

in modo che Rails tenterà effettivamente di salvare lo stesso valore e non lo sostituirà con Time.now.

1

Hai anche decrement e increment (e le relative versioni Bang) che non alterano updated_at, non andare callback validazione trigger e sono ovviamente a portata di mano per i contatori/interi.

Problemi correlati