2009-10-03 13 views
17

Sono a conoscenza di ActiveRecord :: Dirty e dei metodi correlati, ma non vedo un mezzo con cui posso iscriversi a un evento modificato. Qualcosa di simile:Richiamata per attributi ActiveRecord modificati?

class Person < ActiveRecord::Base 
    def attribute_changed(attribute_name, old_value, new_value) 
    end 

    #or 

    attribute_changed do |attribute_name, old_value, new_value| 
    end 
end 

C'è uno standard o un plugin Rails per questo? Sento che deve essere lì da qualche parte e mi manca.

risposta

18

La risposta di cwninja dovrebbe fare il trucco, ma c'è un po 'di più.

Prima di tutto, la gestione degli attributi di base viene eseguita con il metodo write_attribute, quindi è necessario utilizzarlo.

Rails ha anche una struttura di callback incorporata che potrebbe essere piacevole da usare anche se non consente di passare argomenti che sono un po 'fastidiosi.

Uso callback personalizzate che si poteva fare in questo modo:

class Person < ActiveRecord::Base 

    def write_attribute(attr_name, value) 
    attribute_changed(attr_name, read_attribute(attr_name), value) 
    super 
    end 

    private 

    def attribute_changed(attr, old_val, new_val) 
     logger.info "Attribute Changed: #{attr} from #{old_val} to #{new_val}" 
    end 

end 

Se si voleva cercare di utilizzare Rails callback (particolarmente utile se si potrebbe avere più callback e/o sottoclasse) si potrebbe fare qualcosa di simile :

class Person < ActiveRecord::Base 
    define_callbacks :attribute_changed 

    attribute_changed :notify_of_attribute_change 

    def write_attribute(attr_name, value) 
    returning(super) do 
     @last_changed_attr = attr_name 
     run_callbacks(:attribute_changed) 
    end 
    end 

    private 

    def notify_of_attribute_change 
     attr = @last_changed_attr 
     old_val, new_val = send("#{attr}_change") 
     logger.info "Attribute Changed: #{attr} from #{old_val} to #{new_val}" 
    end 

end 
+0

Peter, che bello, mi ha salvato un TON di "write_attribute" che ho sparpagliato in tutto il mio codice. Grazie! – BushyMark

+0

Sembra che questo sia solo per Rails 2. – lulalala

+0

È arrivato a questo tramite google senza verificare la data. Questo passo più recente ha fatto ciò di cui avevo bisogno: [Come tenere traccia delle modifiche di un modello in un 'after_callbacks'] (http://ruby-journal.com/how-to-track-changes-with-after-callbacks-in- rails-3-or-newer /) – Jay

5

prova:

def attribute_changed(attribute_name, old_value, new_value) 
end 

def attribute=(attribute_name, value) 
    returning(super) do 
    attribute_changed(attribute_name, attribute_was(attribute_name), attribute(attribute_name)) 
    end 
end 

appena inventato questo ora, ma dovrebbe funzionare.

+0

Grazie per avermi impostato sulla strada giusta. – Mario

3

si può sempre accedere al metodo privato changed_attributes e verificare le chiavi non si utilizza un before_save e fare con essa ciò che vuoi.

14

Per Rails 3:

class MyModel < ActiveRecord::Base 
    after_update :my_listener, :if => :my_attribute_changed? 

    def my_listener 
    puts "Attribute 'my_attribute' has changed" 
    end 
end 

commentato in: https://stackoverflow.com/a/1709956/316700

non trovo documentazione ufficiale su questo.

+2

Credo che voglia invocare un metodo non appena un attributo viene modificato in memoria, prima che venga chiamato save, ovvero "my_object.some_attr =" foo "' genererebbe un callback. – MikeJ

+0

'after_update' è deprecato dal rails 2.3 (http://apidock.com/rails/ActiveRecord/Callbacks/after_update) – schmijos

2

Il modo più semplice che ho trovato:

after_save :my_method, :if => Proc.new{ self.my_attribute_changed? } 

def my_method 
    ... do stuff... 
end 
+1

after_save: my_method,: if =>: my_attribute_changed? –

+0

bello! è ancora meglio :) – pesta

8

Per Rails 4

def attribute=(value) 
    super(value) 
    your_callback(self.attribute) 
end 

Se si desidera sovrascrivere il valore dell'attributo si dovrebbe usare write_attribute(:attribute, your_callback(self.attribute)) e non attribute= o ti loop su fino a quando non ottieni un'eccezione troppo profonda.

Problemi correlati