Saltare una validazione di un modello condiviso

Ciao a tutti.
Ho un modello “x” con una validazione “y”.
Il modello é usato da due diversi controller “a” e “b”.
Come posso fare in modo che quando “x” viene usato da “a” la validazione
“y” venga eseguita mentre quando “x” viene usato da “b” la validazione
“y” NON venga eseguita?

Grazie a tutte le persone che mi aiuteranno.

Ciao

se parliamo di validazione, devi rivolgere l’attenzione a quello che
avviene NEL modello. quindi se i due controller trattano in modo
differente lo stesso modello, dovrai basare la validazione su quelle
differenze.

se non ci sono differenze, magari puoi usare un solo controller e butti
quello che avanza… :wink:

ciao,
A.

Il 23/06/2010 15:19, pezzuya … ha scritto:

pezzuya … wrote:

Non ho capito.
La validazione é sul contenuto di un campo usato da entrambe i
controller ma in un caso deve essere fatta nell’altro no.

Sistema grezzo: in un controller inizializzi una variabile e sull’altro
no (o la crei su entrambi dandole valori diversi) e tramite un ciclo if
controlli se è presente (o che valore ha) e nel caso gli fai eseguire
quello che ti serve.

Se non c’è niente di più elegante, penso sia l’unica soluzione.

Daneel O.

Andrea P. wrote:

se parliamo di validazione, devi rivolgere l’attenzione a quello che
avviene NEL modello. quindi se i due controller trattano in modo
differente lo stesso modello, dovrai basare la validazione su quelle
differenze.

se non ci sono differenze, magari puoi usare un solo controller e butti
quello che avanza… :wink:

ciao,
A.

Il 23/06/2010 15:19, pezzuya … ha scritto:

Non ho capito.
La validazione é sul contenuto di un campo usato da entrambe i
controller ma in un caso deve essere fatta nell’altro no.

Daneel O. wrote:

pezzuya … wrote:

Non ho capito.
La validazione é sul contenuto di un campo usato da entrambe i
controller ma in un caso deve essere fatta nell’altro no.

Sistema grezzo: in un controller inizializzi una variabile e sull’altro
no (o la crei su entrambi dandole valori diversi) e tramite un ciclo if
controlli se è presente (o che valore ha) e nel caso gli fai eseguire
quello che ti serve.

Se non c’è niente di più elegante, penso sia l’unica soluzione.

Daneel O.

Ci avevo già pensato ma il fatto é che non riesco a sfruttare la
proprietà if delle validazioni. Mi servirebbe un esempio funzionante…

Andrea P. wrote:

si questo � chiaro. quello che ho cercato di dirti � per fare qualcosa
del genere devi focalizzarti sul valore del campo nel modello.
in altre parole, � un po’ assurdo fare validazioni (quindi parliamo di
Model) regolandoti sul Controller usato.

se vuoi farlo, una strada � quella che ti ha indicato Daneel, che � pi�
o meno quello che ti stavo dicendo io (cio� controllare per un
determinato campo, e decidere in base al suo valore se validare o no) :stuck_out_tongue:

ciao,
A.

Il 23/06/2010 15:43, pezzuya … ha scritto:

ok allora supponiamo che non voglia validare perchè il valore che mi é
arrivato ha determinate caratteristiche…

come faccio a dire al modello “adesso non fare la validazione”?

Avevo provato con “save(false)” il problema é che poi non mi veniva
eseguita neanche la after_create :frowning:

si questo è chiaro. quello che ho cercato di dirti è per fare qualcosa
del genere devi focalizzarti sul valore del campo nel modello.
in altre parole, è un po’ assurdo fare validazioni (quindi parliamo di
Model) regolandoti sul Controller usato.

se vuoi farlo, una strada è quella che ti ha indicato Daneel, che è più
o meno quello che ti stavo dicendo io (cioè controllare per un
determinato campo, e decidere in base al suo valore se validare o no) :stuck_out_tongue:

ciao,
A.

Il 23/06/2010 15:43, pezzuya … ha scritto:

detto brevemente:

hai un modello con un ca,po civetta, diciamo che colo chiami
controller_x, è di tipo bool ed è false per default.

poi hai due controller, X e Y: quando userai il modello dal controller
X, setti il campo controller_x = true, altrimenti lo lasci
com’è.

nella validazione del modello, avrai qualcosa del genere:

validates_presence_of :campo_che_ti_pare, :if => Proc.new {|m|
m.controller_x}

o viceversa, fai te :wink: la soluzione è rozza, ma almeno funziona :stuck_out_tongue:

ciao,
A.

Il 23/06/2010 15:59, pezzuya … ha scritto:

ti ho messo un pezzo di codice nell’altra risposta, comunque a grandi
linee funziona
così:
validates_presence_of :campo_che_ti_pare, :if => Proc.new {|m|
m.campo_da_controllare == qualche_valore}

in altre parole, è possibile passare una condizione alla validazione per
decidere se eseguirla o meno. puoi usare sia :if che :unless ed
ovviamente è usabile anche per altri metodi di validazione :wink:

qui trovi una spiegazione più completa:

ciao,
A.

Il 23/06/2010 16:12, pezzuya … ha scritto:

Andrea P. wrote:

detto brevemente:

hai un modello con un ca,po civetta, diciamo che colo chiami
controller_x, � di tipo bool ed � false per default.

poi hai due controller, X e Y: quando userai il modello dal controller
X, setti il campo controller_x = true, altrimenti lo lasci
com’�.

nella validazione del modello, avrai qualcosa del genere:

validates_presence_of :campo_che_ti_pare, :if => Proc.new {|m|
m.controller_x}

o viceversa, fai te :wink: la soluzione � rozza, ma almeno funziona :stuck_out_tongue:

ciao,
A.

Il 23/06/2010 15:59, pezzuya … ha scritto:

Ora é più chiaro…
ma non riesco comunque a farlo girare.
Nel modello “document” ho messo:

attr_accessor :esegui

validate :valid_content_type?, :if => Proc.new {|m| m.esegui == true}

def initialize(params = nil)
self.esegui = true
end

nel controller ho messo:
@document = Document.new(params[:document])
@document.esegui = false

ma quando fà ccio la save mi dà un errore di nil object

hai creato il campo sul db?

inoltre non occorre sovrascrivere il costruttore, nè mettere gli
attributi di accesso. basta averlo sul db. in caso puoi creare un campo
fake ma non è la soluzione più veloce :stuck_out_tongue:

ciao,
A.

Il 23/06/2010 16:47, pezzuya … ha scritto:

Andrea P. wrote:

hai creato il campo sul db?

inoltre non occorre sovrascrivere il costruttore, n� mettere gli
attributi di accesso. basta averlo sul db. in caso puoi creare un campo
fake ma non � la soluzione pi� veloce :stuck_out_tongue:

ciao,
A.

Il 23/06/2010 16:47, pezzuya … ha scritto:

ma con attr_accessor non ho creato un attributo virtuale? (esegui)
perchè c’è la necessità di creare un campo sul db?

dipende come devi accedere a quell’attributo, spesso devi far credere ad
ActiveRecord di avere quei campi su una tabella (per esempio quando vuoi
applicargli le validazioni), in quel caso crei dei campi fake in un
altro modo.

nel tuo caso, se proprio vuoi farlo così, prova:

attr_accessor :esegui

def initialize(params = nil)
self.esegui = true
super
end

cioè chiami il costruttore originale con ‘super’ :stuck_out_tongue:

Il 23/06/2010 17:06, pezzuya … ha scritto:

la spiegazione è che quando crei un’istanza di una classe derivata da
ActiveRecord::Base necessariamente in fase di costruzione deve
conoscere i campi della tabella che rappresenta, altrimenti come fa a
sapere quali attributi ha un certo modello? :wink:

queste operazioni avvengono, di norma, nella fase di costruzione
dell’oggetto, quindi “initialize”. quando dichiari il metodo initialize
nel modello, di fatto stai sovrascrivendo un comportamento di default: è
lecito farlo, ma poi devi chiamare anche il metodo originario,
dichiarato in qualche classe-padre, per inizializzare l’oggetto come
previsto.

perciò non stai agendo su quel metodo, lo chiami e basta :slight_smile:

tanto per completare, spesso può essere necessario farlo anche quando
sovrascrivi un metodo setter, per esempio se hai un attributo ‘name’
in un modello ma vuoi che faccia qualcosa di diverso dal previsto quando
imposti un valore su quel campo:

def name=(value)

operazioni custom

super # chiamo il metodo originario…
end

ciao,
A.

Il 23/06/2010 18:26, pezzuya … ha scritto:

Andrea P. wrote:

dipende come devi accedere a quell’attributo, spesso devi far credere ad
ActiveRecord di avere quei campi su una tabella (per esempio quando vuoi
applicargli le validazioni), in quel caso crei dei campi fake in un
altro modo.

nel tuo caso, se proprio vuoi farlo cos�, prova:

attr_accessor :esegui

def initialize(params = nil)
self.esegui = true
super
end

cio� chiami il costruttore originale con ‘super’ :stuck_out_tongue:

Il 23/06/2010 17:06, pezzuya … ha scritto:

Ora funziona…ho visto qualche esempio e come hai scritto giustamente
tu ci voleva “super” anche se non ho capito bene perché :slight_smile:
perché bisogna agire su initialize della classe padre (in questo caso
Activerecord::Base) rimane per me un mistero…

esplicito per chiarezza le parti di codice che ho dimenticato:

class Document < ActiveRecord::Base
end

class PossiblyInvalidDocument < Document
#no validations here
end

class DefinitelyValidDocument < Document
validates_presence_of :text

other validations

end

pezzuya … wrote:

Ciao a tutti.
Ho un modello “x” con una validazione “y”.
Il modello é usato da due diversi controller “a” e “b”.
Come posso fare in modo che quando “x” viene usato da “a” la validazione
“y” venga eseguita mentre quando “x” viene usato da “b” la validazione
“y” NON venga eseguita?

Grazie a tutte le persone che mi aiuteranno.

Ciao

Mi pare di capire che tu abbia già risolto il problema grazie all’aiuto
dei partecipanti alla discussione, pertanto se ti andava volevo
filosofeggiare un pochino sul tuo problema: come mai ti ritrovi a voler
eseguire le validazioni sul modello su un controller e no su un altro?
Voglio dire, è una situazione un po’ strana: nulla vieta infatti al
controller coi superpoteri di creare record invalidi nel db, cosa che mi
sembra potenzialmente pericolosa.

Ah, un’altra possibile soluzione al problema credo sarebbe potuta essere
sfruttare la single table inheritance: ti crei un modello base con due
sottomodelli, tipo questi:

class Document
end

class PossiblyInvalidDocument
#no validations here
end

class DefinitelyValidDocument
validates_presence_of :text

other validations

end

e poi nei controller crei il tipo di documento che ti serve.

Ciao
Andrea

Andrea P. wrote:

la spiegazione � che quando crei un’istanza di una classe derivata da
ActiveRecord::Base necessariamente in fase di costruzione deve
conoscere i campi della tabella che rappresenta, altrimenti come fa a
sapere quali attributi ha un certo modello? :wink:

queste operazioni avvengono, di norma, nella fase di costruzione
dell’oggetto, quindi “initialize”. quando dichiari il metodo initialize
nel modello, di fatto stai sovrascrivendo un comportamento di default: �
lecito farlo, ma poi devi chiamare anche il metodo originario,
dichiarato in qualche classe-padre, per inizializzare l’oggetto come
previsto.

perci� non stai agendo su quel metodo, lo chiami e basta :slight_smile:

tanto per completare, spesso pu� essere necessario farlo anche quando
sovrascrivi un metodo setter, per esempio se hai un attributo ‘name’
in un modello ma vuoi che faccia qualcosa di diverso dal previsto quando
imposti un valore su quel campo:

def name=(value)

operazioni custom

super # chiamo il metodo originario…
end

ciao,
A.

Il 23/06/2010 18:26, pezzuya … ha scritto:

Scusa ieri non ho avuto tempo di risponderti…
Praticamente mi stai dicendo che tutte le classi hanno un costruttore di
default (initializer) ma che operando nel mio modo sono andato a
sovrascriverlo settando un solo attributo. Questo ha fatto sì che avendo
settato un solo attributo gli altri non sono stati inizializzati e
quindi é stato necessario richiamare “super” affinchè anche questi
venissero inizializzati…ho capito bene?

Andrea L. wrote:

pezzuya … wrote:

Ciao a tutti.
Ho un modello “x” con una validazione “y”.
Il modello é usato da due diversi controller “a” e “b”.
Come posso fare in modo che quando “x” viene usato da “a” la validazione
“y” venga eseguita mentre quando “x” viene usato da “b” la validazione
“y” NON venga eseguita?

Grazie a tutte le persone che mi aiuteranno.

Ciao

Mi pare di capire che tu abbia già risolto il problema grazie all’aiuto
dei partecipanti alla discussione, pertanto se ti andava volevo
filosofeggiare un pochino sul tuo problema: come mai ti ritrovi a voler
eseguire le validazioni sul modello su un controller e no su un altro?
Voglio dire, è una situazione un po’ strana: nulla vieta infatti al
controller coi superpoteri di creare record invalidi nel db, cosa che mi
sembra potenzialmente pericolosa.

Ah, un’altra possibile soluzione al problema credo sarebbe potuta essere
sfruttare la single table inheritance: ti crei un modello base con due
sottomodelli, tipo questi:

class Document
end

class PossiblyInvalidDocument
#no validations here
end

class DefinitelyValidDocument
validates_presence_of :text

other validations

end

e poi nei controller crei il tipo di documento che ti serve.

Ciao
Andrea

Mi serviva perchè avevo due controller che condividevano lo stasso
modello. In un caso dovevo effettuare una validazione sul formato del
file caricato mentre nell’altro no (me lo avevano richiesto
esplicitamente). L’utilizzo dell’ereditarietà tra modelli l’avevo giÃ
pensata e utilizzata in un’altra occasione e resta secondo me la
soluzione “più pulita”. Però in questo caso mi tornava utile “andare
sullo sporco” per 1)imparare qualcosa di nuovo 2)evitare di andare a
toccare cose che erano già testate e funzionanti.

pezzuya … wrote:

Mi serviva perchè avevo due controller che condividevano lo stasso
modello. In un caso dovevo effettuare una validazione sul formato del
file caricato mentre nell’altro no (me lo avevano richiesto
esplicitamente).

Ma come mai ti hanno fatto una richiesta simile? Ci sono motivazioni
reali? Voglio dire, è lecito che il cliente mi chieda qualsiasi
porcheria, io poi gli rispondo che così no non va bene, ovviamente se
poi insiste faccio come vuole lui, visto che mi paga, ma c’è da stare
attenti.
Gli devo dire anche che oggi il codice funziona, sembra non creare
particolari problemi (se il fatto di accettare record non validati non è
un problema) ma è facile che codice come questo prima o poi ti morda la
mano, e il malaugurato giorno che ci sarà da modificare qualcosa o
fixare il problema potrebbe volerci molto più tempo (e quindi denaro da
parte sua), e che quindi io me ne lavo le mani… uomo avvistato mezzo
salvato.