Rails: modello con più "super-modelli" (?)

Ciao a tutti,
mi trovo ad affrontare un problema con rails che non ho mai affrontato e
mi piacerebbe sapere qual’ il metodo pi giusto per risolverlo :slight_smile:

Vi espongo il problema:
nell’app c’ un modello “Persona”, che potrebbe trovarsi in queste
situazioni:

  • essere e rimanere sempre soltanto una persona
  • diventare uno “Studente”, quindi acquisire nuovi attributi (tipo n. di
    matricola), mantenendo quelli di “Persona”
  • diventare un “Pendolare”, anche in questo caso acquisendo nuovi
    attributi (tipo n. di abbonamento) mantenendo quelli di persona
  • diventare sia uno studente che un pendolare, rimanendo una persona ma
    acquisendo gli attributi sia di uno studente che di un pendolare

il tutto ovviamente in rails, quindi con validazioni, relazioni, ecc.

Al volo la soluzione che mi sarebbe venuta in mente quella di fare un
modello Persona che ha una relazione 1-1 con Pendolare e con Studente,
ma in questo modo sto trattando i tre modelli come entit veramente
separate, mentre logicamente non lo dovrebbero essere. Inoltre dovrei,
presa una persona, richiedere un dato di studente con
“persona.studente.n_matricola”, mentre sarebbe ottimo fare
“persona.n_matricola” che mi restituisce false o nil se la persona non
uno studente

Esiste in rails “qualcosa” per fare quello che devo fare?
se ho chiesto una cosa banale accetto anche infamate, sempre che siano
accompagnate da un link da leggermi! :slight_smile:

Persona e pendolare sono due variabili boolean… Io farei cosi… Ma
soni
grezzo
Il giorno 05/giu/2012 21:37, “Tommaso V.”
[email protected]
ha scritto:

Ciao,
la tua intuizione mi sembra corretta, ma userei dei nomi diversi per
evitare confusione. Il concetto che tu hai un modello
Persona che si pu arricchire di diverse abilit a seconda del proprio
stato. Farei una cosa del genere:

class Person
has_one :student_ability
has_one :pendular_ability
end

Ovviamente has_one ha senso solo se gli altri modelli istanze di
ActiveRecord, altrimenti ti basta una cosa del genere:

class Person
def student_ability
StudentAbility.new(self)
end

end

Dopo di che puoi delegare dal modello Person verso i rispettivi oggetti
di cui si compone:

class Person
delegate :n_matricola, :to => :student_ability

end

che per solleva una eccezione se il modello student_ability nil.

Ma voi non usereste un Decorator Pattern? Ma poi come lo mappo ?

class Person
attr_accessor :name
end

module Behaviors

module Student
def registration_number # write me
end
end

module Pendular
def subscription_number # write me
end
end
end

tizio = Person.new
tizio.extend Behaviors::Student
tizio.registration_number

caio = Person.new
caio.extend Behaviors::Pendular
caio.subscription_number

E’ un’eresia?
Ovviamente, questi sarebbero solo PORO ma persisterli non dovrebbe
essere
impossibile.

Maurizio

My profile https://plus.google.com/100973969013103507046/about

2012/6/5 Riccardo L. [email protected]


Riccardo

Il giorno 05/giu/2012, alle ore 23:12, Emanuele DelBono
[email protected] ha scritto:

Ma voi non usereste un Decorator Pattern? Ma poi come lo mappo ?

+1
Stessa idea stesso dubbio

Domande…
Non meglio fare due moduli separati?
possibile gi in un modulo inserire qualche riferimento ad
activerecord in modo che mappi i campi da se?

possibile invertire la cosa? Mi spigo… Fare un modulo Persona da
includere in 3 classi: Studente, Pendolare e StudentePendolare?


Riccardo

Il giorno 06/giu/2012, alle ore 00:36, maurizio de magnis
[email protected] ha scritto:

Non conoscevo il metodo extend…e quando vedo questo codice mi
emoziono. <3 ruby!

2012/6/6 maurizio de magnis [email protected]:

Che vuoi dire?

Non userei dei moduli in questo caso, a meno che non si debba
condividere il comportamento tra due classi, ma qui la classe Person
una sola.
Non sarebbe diverso dal mettere i metodi direttamente nella classe, non
vedo benefici, i metodi conditnuano a condividere le variabili di
istanza e le responsabilit della classe non diminuiscono.

On Wed, Jun 6, 2012 at 9:47 AM, Fabrizio R. [email protected]
wrote:

Che vuoi dire?

Intendevo che una volta creata la struttura per implementare un
Decorator, riesco a persisterla con ActiveRecord? (con NHibernate ce
la faccio, con RoR non so…)

ema
http://blog.codiceplastico.com/ema

Interessante. Non ho mai usato questo livello di metaprogrammazione per
risolvere un problema del genere.

2012/6/6 Fabrizio R. [email protected]

Non userei dei moduli in questo caso, a meno che non si debba condividere
il comportamento tra due classi, ma qui la classe Person una sola.

Non sarebbe diverso dal mettere i metodi direttamente nella classe, non

vedo benefici, i metodi conditnuano a condividere le variabili di istanza e
le responsabilit della classe non diminuiscono.

Pensavo alla transizioni che avverrebbero in un oggetto inizialmente
Person, poi augmentato con il behavior di Student e successivamente di
Pendular.

class Person
def augment(behavior)
extend Behaviors.const_get(behavior)
end
end

pinky = Person.new

pinky now goes to school!

pinky.augment :Student
pinky.respond_to? :registration_number # => true

pinky now uses public transports!

pinky.augment :Pendular
pinky.respond_to? :subscription_number # => true

Ovviamente, nell’ipotesi che questi stati non siano mutuamente
esclusivi.

Maurizio

My profile https://plus.google.com/100973969013103507046/about

Maurizio De magnis wrote in post #1063303:

[CUT]

Complimenti per la soluzione però non mi sembra utile, da qualche parte
devi memorizzarle quelle informazioni …o sai qualcosa che io non so???
(chiedo, dopo quell magia non si sa mai)

Secondo me l’unica fattibile è la relazione 1-1, la prima proposta da
Fabrizio. Se l’eccezione del delegate è un problema puoi sempre
definirti tu i metodi:

class Person
def n_matricola
self.student.try :n_matricola
end
end

Il 06/06/12 12:33, Marco M. ha scritto:

Complimenti per la soluzione per non mi sembra utile, da qualche parte
devi memorizzarle quelle informazioni …o sai qualcosa che io non so???
(chiedo, dopo quell magia non si sa mai)

Le varie soluzioni sono molto interessanti, ma quel che mi preoccupa
proprio il rapporto con activerecord e il db. Anche a me la 1-1 mi
sembra la pi “pulita” per quanto riguarda poi la persistenza dei dati
senza dover scrivere un sacco di codice nel modello Person

Secondo me l’unica fattibile la relazione 1-1, la prima proposta da
Fabrizio. Se l’eccezione del delegate un problema puoi sempre
definirti tu i metodi:

class Person
def n_matricola
self.student.try :n_matricola
end
end

Credo che il parametro :allow_nil => true di delegate eviti proprio
l’eccezione indicata da fabrizio:

class Person
delegate :n_matricola, :to => :student_ability, :allow_nil => true

end

http://api.rubyonrails.org/classes/Module.html#method-i-delegate

Forse sono rimasto indietro con rails. che ormai fa cose che voi umani
non potreste immaginare, ma rimane la relazione modello==tabella giusto?

E come implementi il polimorfismo in una tabella MySQL?

Personalmente, parto da questo assunto (sbagliato?): e’ impossibile
implementare il polimorfismo con tabelle MySQL.

Di conseguenza servono degli escamotage.

Delle soluzioni proposte (scusate la mia risposta criptica: rispondevo
da mobile e ho le dita grosse)

Questa mi sembra la pi semplice da implementare:

class Person
has_one :student_ability
has_one :pendular_ability
end

(quella di Fabrizio R.)

Ricordandosi ovviamente di considerare il caso in cui student_ability e’
nil

Ciao!