Forum: Italian Ruby user group Rails: modello con più "super-modelli" (??)

Posted by Tommaso Visconti (Guest)
on 2012-06-05 21:37
(Received via mailing list)
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 :)

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! :)
Posted by Davide Rambaldi (Guest)
on 2012-06-05 22:32
(Received via mailing list)
Persona e pendolare sono due variabili boolean... Io farei cosi... Ma 
soni
grezzo
Il giorno 05/giu/2012 21:37, "Tommaso Visconti" 
<tommaso.visconti@gmail.com>
ha scritto:
Posted by Fabrizio Regini (Guest)
on 2012-06-05 22:49
(Received via mailing list)
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.
Posted by Emanuele DelBono (Guest)
on 2012-06-05 23:13
(Received via mailing list)
Ma voi non usereste un Decorator Pattern? Ma poi come lo mappo ?
Posted by Riccardo Lucatuorto (riccardo_l)
on 2012-06-05 23:26
(Received via mailing list)
----
Riccardo

Il giorno 05/giu/2012, alle ore 23:12, Emanuele DelBono
<emanuele.delbono@gmail.com> ha scritto:

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

+1
Stessa idea stesso dubbio
Posted by Maurizio De magnis (olistik)
on 2012-06-06 00:36
(Received via mailing list)
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 Lucatuorto <gnuduncan@gmail.com>
Posted by Emanuele DelBono (Guest)
on 2012-06-06 08:46
(Received via mailing list)
Non conoscevo il metodo extend...e quando vedo questo codice mi
emoziono. <3 ruby!

2012/6/6 maurizio de magnis <maurizio.demagnis@gmail.com>:
Posted by Riccardo Lucatuorto (riccardo_l)
on 2012-06-06 08:55
(Received via mailing list)
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
<maurizio.demagnis@gmail.com> ha scritto:
Posted by Fabrizio Regini (Guest)
on 2012-06-06 09:48
(Received via mailing list)
Che vuoi dire?
Posted by Fabrizio Regini (Guest)
on 2012-06-06 09:54
(Received via mailing list)
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.
Posted by Emanuele DelBono (Guest)
on 2012-06-06 10:05
(Received via mailing list)
On Wed, Jun 6, 2012 at 9:47 AM, Fabrizio Regini <freegenie@gmail.com> 
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
Posted by Maurizio De magnis (olistik)
on 2012-06-06 10:26
(Received via mailing list)
2012/6/6 Fabrizio Regini <freegenie@gmail.com>

> 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>
Posted by Fabrizio Regini (Guest)
on 2012-06-06 10:55
(Received via mailing list)
Interessante. Non ho mai usato questo livello di metaprogrammazione per 
risolvere un problema del genere.
Posted by Davide Rambaldi (Guest)
on 2012-06-06 12:08
(Received via mailing list)
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 Regini)

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

Ciao!
Posted by Marco Mastrodonato (marcomd)
on 2012-06-06 12:33
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
Posted by Tommaso Visconti (Guest)
on 2012-06-06 12:50
(Received via mailing list)
Il 06/06/12 12:33, Marco Mastrodonato 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#met...
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.