Utilizzo delle callbacks in rails

Ciao,
sto modificando un’applicazione rails 3.2 grossa e complessa più di
quando dovrebbe essere a causa del solito problema che il tempo causa.
Un modello ha 16 callbacks, alcune delle quali richiamate in cascata più
di una volta e vorrei fare un pò di ordine.

Ne approfitto per fare un riepilogo.
Rails permette di saltare le callback utilizzando metodi di
aggiornamento specifici, tutte o niente:

Ci sono altri modi per disattivarle:

Se una specifica callback potrebbe non essere sempre necessaria si può
implementare solo quando serve, non so se funziona con rails 4:

Disattivare una callback ha effetto permanente:
Model.skip_callback :cosa, :quando, :callback

esempio:

Article.skip_callback :save, :after, :aggiorna_relazioni

e va ripristinata con:

Model.set_callback :cosa, :quando, :callback

A me verrebbe comodo impostare uno skip temporaneo ad esempio
dall’istanza del modello che una volta distrutta venissero ripristinate
le callback originali, ma non si può.
Qualche escamotage?

Ciao Marco, come al solito ti faccio delle proposte indecenti :slight_smile:

Se il tuo scopo è sanare la situazione di un modello A in cui le
callback
C[] ne riducono la flessibilità, allora potrebbe avere senso introdurre
una
classe Active Record B “specchio” contenente inizialmente solo le
relazioni
di A.
In seguito, con l’ottica del dare un colpo alla botte e uno al cerchio,
potresti migrare gradualmente le funzionalità da A a B, esternalizzando
altri oggetti la logica presente in C[].

Ti consiglio invece l’approccio dello skip temporaneo solo se:

  • A non è troppo grossa/incasinata
  • devi fare una sola modifica ad A

in tal caso un approccio forse grezzo consiste nello specificare una
condizione di esecuzione di ogni callback presente.

Da:

class A < ActiveRecord::Base
validate :v1, on: :destroy
validate :v2
validate :v3
validate :v4
validates_presence_of :field1

public methods and stuff

end

A:

class A < ActiveRecord::Base
validate :v1, on: :destroy, if: :should_validate
validate :v2, if: :should_validate
validate :v3, if: :should_validate
validate :v4, if: :should_validate
validates_presence_of :field1, if: :should_validate

attr_accessor :should_validate

public methods and stuff

end

E silenziando le validazioni nei contesti che ti servono:

a = A.find(23)
a.should_validate = false
a.destroy

N.B.: non ho testato questo codice :slight_smile:

2015-02-24 14:50 GMT+01:00 Marco M.
[email protected]:

Ogni volta che mi capita di avere una callback che non deve essere
invocata in particolari circostanze, uso delle variabili di istanza:

class A
attr_accessor :skip_uniqueness_validation

validates_uniqueness_of :field, unless: :skip_uniqueness_validation
end

my_record = A.first
my_record.skip_uniqueness_validation = true
my_record.field = ‘a possibile duplciate’
my_record.save

con lo stesso metodo puoi skippare altri callback, anche mettendo una
condizione all’inizio del blocco di codice che non deve essere
eseguito.

-f

2015-02-24 14:50 GMT+01:00 Marco M.
[email protected]:

:slight_smile:
Altra cosa che che si pu fare per skippare le validazioni usare
update_columns invece che update_attributes.

2015-02-24 16:46 GMT+01:00 maurizio de magnis
[email protected]:

Giusta la considerazione di usare l’unless al posto dell’if,
considerando
la variabile di controllo di default a false (lasciando quindi attive le
validazioni) e impostandola manualmente a true nei contesti desiderati.
Nell’esempio di prima ho invertito il valore di verit… ^_^’

@Maurizio
Si non ti preoccupare, cercavo solo l’idea.
Il modello “clone” e’ una buona soluzione per sanare un modello
incasinato e cerchero’ di ricordarmela. Non credo sia semplice da
attuare in un progetto poco ordinato dove il modello in questione è
utilizzato in tutte le salse. Speravo di cavarmela con meno impegno.

@Fabrizio
credo che il metodo che proponi con la variabile di istanza sia il
migliore per saltare la callback.

Grazie ad entrambi, siete troppo avanti