Forum: Rails-ES ActiveRecord y herencia multitabla

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
6f952bee7570a3db2ecba5b06c0062b3?d=identicon&s=25 Fernando Guillen (fguillen)
on 2009-01-08 13:28
(Received via mailing list)
Hola gente,

Estaba yo tan contento intentando implementar una herencia con
ActiveRecord y veo que lo tiene complementamente magificado:
simplemente poniendo un campo type:string en la clase padre todo se
hace mágicamente.

Triste de mí al darme cuenta que cuando la documentación dice "Single
table inheritance" quiere decir exactamente eso: "Single table
inheritance".

Y claro yo mirando los logs y viendo que sólo se hace un insert into
en la tabla de la clase padre y la tabla de la clase hijo es
completamente ignorada..

Esto está bien si la clase padre y la clase hijo comparten
absolutamente todos los atributos, pero qué hay si quiero, como es
completamente comprensible, incluir un atributo en una clase hija que
no quiero que esté en la clase padre.. pues que no se puede..

Obie resuelve un poco esto con métodos de instancia.. y aliases.. [1]
pero no es lo mismo :)

Verdaderamente me parece un implementación de herencia muy muy limitada.

Entonces vuelvo a google con la búsqueda más concreta "activerecord
multi table inheritance" y encuentro este currado post [2] a propósito
de como implementar este tipo de herencia pero me resulta demasiado
confuso, tortuoso y postgresql dependiente...

Mi pregunta es: ¿existe alguna manera sencilla y si es posible bien
testeada de implementar la herencia multitabla con Rails?

Por ahora estoy valorando usar relaciones polimórficas para que los
objetos que deberían ser los hijos pasen a ser contenedores de la
clase padre a través de un has_one polimófico.. como se explica
aquí:[3], ésta es la aproximación que al principio se me indicó pero no me
parecía demasiado correcta.. aunque ahora he cambiado de opinión: no
será la correcta pero es la más directa.

Cualquier comentario es bien venido.

Gracias.

f.

[1] http://www.jroller.com/obie/entry/some_ar_sugar_4_u
[2]
http://lindsaar.net/2008/3/12/multi-table-inherita...
[3] http://www.ibm.com/developerworks/web/library/wa-rails3/

--
Fernando
GuillénDesarrollador Web Freelance
http://www.fernandoguillen.info
8da2a535c50603e3252fb423b6005309?d=identicon&s=25 Christos Zisopoulos (Guest)
on 2009-01-08 13:35
(Received via mailing list)
Hola Fernando,

La idea de STI es que la tabla padre tiene *todos* los atributos de
todas las clases 'hijas'.

Si vees que las clases hijas no comparten muchos atributos con la
clase padre, es un code smell que significa que la herencia no te vale
en esta
ocasión.
Del libro del Agile Web Dev w/ rails:

David Says. . .
Won’t Subclasses Share All the Attributes in STI?
Yes, but it’s not as big of a problem as you think it would be. As
long as the sub-
classes are more similar than not, you can safely ignore the
reports_to attribute
when dealing with a customer. You simply just don’t use that attribute.
We’re trading the purity of the customer model for speed (selecting
just from
the people table is much faster than fetching from a join of people
and customers
tables) and for ease of implementation.
This works in a lot of cases, but not all. It doesn’t work too well
for abstract rela-
tionships with very little overlap between the subclasses. For
example, a con-
tent management system could declare a Content base class and have sub-
classes such as Article, Image, Page, and so forth. But these
subclasses are likely
to be wildly different, which will lead to an overly large base table
because it
has to encompass all the attributes from all the subclasses. In this
case, it would
be better to use polymorphic associations, which we describe next.

-christos
E962ae295d82a05193cc180c12bda5d8?d=identicon&s=25 Juan JosŽé Vidal Agust’ín (Guest)
on 2009-01-08 13:36
(Received via mailing list)
Ultimamente yo también estoy pensando en cosas parecidas, y lo veo todo
muy oscuro.
Mi idea es hacer un clase abstracta, y que las subclases hereden de
ella, teniendo estas diferentes comportamientos en base a su naturaleza.

Estoy pensando en utilizar mixin a través de módulos paraa conseguir
"Herencia Múltiple".
No tengo muy claro como hacerlo.... No he encontrado ninguna aplicación
libre en rails que implemente algo así.

Por ejemplo: Una clase Proyecto y varias clases Subproyecto, cada una
con vistas diferentes.

¿Conocéis dónde puedo encontrar información relativa a esto?

Estoy leyendo concienzudamente "Enterprise Rails", y parece que veo algo
de luz, pero algo se me escapa... no termino de verlo claro. Me gustaría
ver código Rails haciendo esto.

Un saludo!

Fernando Guillen escribió:
Fc3f12c165eaeac4999bc274215fb582?d=identicon&s=25 Roberto m. Oliva (roliva)
on 2009-01-08 13:42
(Received via mailing list)
Hola

Puedes hacer lo que buscas con STI. Basta que la tabla contenga el mayor
conjunto de campos posible entre las clases padre y las hijas. Aquellas
clases que no implementen ciertos atributos simplemente llenaran el
valor del campo con un valor por defecto, por ejemplo nulo.

Puede parecer una implementacion un tanto chapuza, pero la verdad es que
funciona bastante bien dentro de Rails y tiene mejor rendimiento que
utilizar MTI. El problema radica en el uso inútil de espacion en la BD
que sabes que nunca vas a llenar.

Un saludo
Roberto M. Oliva

Fernando Guillen
escribió:> Hola gente,
F625b891618be8ec32547a07b3192bb0?d=identicon&s=25 Francesc Esplugas (fesplugas)
on 2009-01-08 14:57
(Received via mailing list)
2009/1/8 Roberto M. Oliva <roliva@idecnet.com>:

> Puedes hacer lo que buscas con STI. Basta que la tabla contenga el mayor
> conjunto de campos posible entre las clases padre y las hijas. Aquellas
> clases que no implementen ciertos atributos simplemente llenaran el
> valor del campo con un valor por defecto, por ejemplo nulo.

Y utilizar STI con "aggregations"?
6f952bee7570a3db2ecba5b06c0062b3?d=identicon&s=25 Fernando Guillen (fguillen)
on 2009-01-08 15:37
(Received via mailing list)
El día 8 de enero de 2009 13:42, Roberto M. Oliva <roliva@idecnet.com>
escribió:> Hola
>
> Puedes hacer lo que buscas con STI. Basta que la tabla contenga el mayor
> conjunto de campos posible entre las clases padre y las hijas. Aquellas
> clases que no implementen ciertos atributos simplemente llenaran el
> valor del campo con un valor por defecto, por ejemplo nulo.

Es que el uso de STI también tiene otra pega y es la imposibilidad de
usar validaciones a nivel BD de la no nulicidad de los campos: si un
campo es sólo usado por una clase hija pero quieres ponerle un null =>
false en la migración para asegurar de que este campo está bien
inicializado no vas a poder pues te petarán todas las clases
'hermanas'. Sí ya sé que esto se puede proteger con validaciones de
rails, pero no las podrás poner a nivel de BD.. aunque sé que para
muchos esto no es un problema..  y para mí tampoco lo sería sino le
sumásemos todas las otras pegas que le encuentro.

>
> Puede parecer una implementacion un tanto chapuza, pero la verdad es que
> funciona bastante bien dentro de Rails y tiene mejor rendimiento que
> utilizar MTI. El problema radica en el uso inútil de espacion en la BD
> que sabes que nunca vas a llenar.

A parte de que la tabla padre queda hecha un burruño de campos
posiblemente muy inconexos.. sin contar con el problema de no poder
usar el mismo nombre para dos atributos de clases hijas independientes
cuyo tipo de dato no es el mismo.. o cualquier incompatibilidad.

Sin contar tampoco con no saber de ninguna manera qué campos se han
incluido para completar una de las clases hijas y cuales para la otra.

Además de andar todo el rato modificando la tabla padre cada vez que
aparece una nueva clase hija con atributos personalizados.

No sé.. será más óptimo pero me parece una justificación un poco
paradógica partiendo de la base de que estamos usando un motor de
persistencia precisamente porque preferimos la agilidad, la
abstracción y la magia a la
optimización.
Saludetes
f.
6f952bee7570a3db2ecba5b06c0062b3?d=identicon&s=25 Fernando Guillen (fguillen)
on 2009-01-08 15:53
(Received via mailing list)
El día 8 de enero de 2009 14:57, Francesc Esplugas
<francesc.esplugas@gmail.com>
escribió:> 2009/1/8 Roberto M. Oliva <roliva@idecnet.com>:
>
>> Puedes hacer lo que buscas con STI. Basta que la tabla contenga el mayor
>> conjunto de campos posible entre las clases padre y las hijas. Aquellas
>> clases que no implementen ciertos atributos simplemente llenaran el
>> valor del campo con un valor por defecto, por ejemplo nulo.
>
> Y utilizar STI con "aggregations"?

Uff, No llego Francesc, ya me lío para entender las aggregations como
para saber como se pueden usar para dar una solución elegante a este
problema.. tienes algún sitio donde expliquen el acercamiento a esta
solución?
:/

f.
348246701cfdb2130b842fd839751a18?d=identicon&s=25 Raul Murciano (raul)
on 2009-01-08 16:03
(Received via mailing list)
Desconozco alternativas mejores a las que habéis comentado (es posible
que otros patrones de acceso a datos los ofrezcan pero hablamos de
ActiveRecord), pero se me ocurre plantear: si las clases herederas son
tan independientes entre sí y te preocupa tanto su mantenimiento en un
futuro... ¿has pensado en manejar su estructura y almacenamiento en la
base de datos de forma independiente (en tablas separadas) y gestionar
su comportamiento el comportamiento común mediante mixins? De esta
forma podrías mantener el DRY donde IMHO de verdad importa (a nivel de
código) y no donde puede ser un estorbo (en la base de datos).
6f952bee7570a3db2ecba5b06c0062b3?d=identicon&s=25 Fernando Guillen (fguillen)
on 2009-01-08 16:19
(Received via mailing list)
2009/1/8 Raul Murciano <raul@murciano.net>:
> Desconozco alternativas mejores a las que habéis comentado (es posible
> que otros patrones de acceso a datos los ofrezcan pero hablamos de
> ActiveRecord), pero se me ocurre plantear: si las clases herederas son
> tan independientes entre sí y te preocupa tanto su mantenimiento en un
> futuro... ¿has pensado en manejar su estructura y almacenamiento en la
> base de datos de forma independiente (en tablas separadas) y gestionar
> su comportamiento el comportamiento común mediante mixins?

En realidad no son tan diferentes.. la clase hijo sólo contiene un par
de métodos que no contiene la clase padre.. por ahora. El 'por ahora'
también es otra causa del porque no quiero usar STI pues no quiero que
porque un hijo más adelante requiera un nuevo atributo tener que
modificar la clase padre influyendo indirectamente a todas las clases
'hermanas' :/

Tu idea está en nuestra cabeza claro.. lo que pasa que nos
gustaríatener en una sola tabla todas las referencias e este tipo de objetos,
que para hacerlo más claro se trata de referencias a ficheros en S3 y
los hijos serían Photo, UserFile, Avatar, ...

La idea de usar mixins, includes, módulos y demás me parece un poco
liosa y críptica, no sé, seguramente porque no estoy acostumbrado y
todavía se me escapa de la cabeza... lo que me apetece es una
implementación que la leas y la entiendas a la primera :/


> De esta
> forma podrías mantener el DRY donde IMHO de verdad importa (a nivel de
> código) y no donde puede ser un estorbo (en la base de datos).

Sip no me molesta tanto que la BD quede poco DRY.. pero por lo que te
comento arriba perderíamos la centralización de este tipo de objetos.

Abrazotes.
f.
33a24a134536b312b0d5334c2a9152db?d=identicon&s=25 Pablo Formoso Estrada (Guest)
on 2009-01-08 16:34
(Received via mailing list)
A mi la primera vez que me planteé usar herencia con Rails me choco un
poco
pero lo hice con STI y ahora me arrepiento, pero tu idea de usar
polimorfismos
me parece bastante aceptable (aún que no correcta) para simularla.

Además no es una característica que se contemple implementar en
Rails... :(
94ac01209314464490a94b47f051be0b?d=identicon&s=25 alarkspur (Guest)
on 2009-01-08 16:35
(Received via mailing list)
Por si te sirve existe el plugin
http://research.inplanb.com/has_ancestor

Saludos.


El 08/01/2009, a las 16:18, Fernando Guillen
escribió:
> 2009/1/8 Raul Murciano <raul@murciano.net>:
348246701cfdb2130b842fd839751a18?d=identicon&s=25 Raul Murciano (raul)
on 2009-01-08 16:42
(Received via mailing list)
El día 8 de enero de 2009 16:18, Fernando Guillen
<fguillen.mail@gmail.com>
escribió:> En realidad no son tan diferentes.. la clase hijo sólo contiene un 
par
> de métodos que no contiene la clase padre.. por ahora. El 'por ahora'
> también es otra causa del porque no quiero usar STI pues no quiero que
> porque un hijo más adelante requiera un nuevo atributo tener que
> modificar la clase padre influyendo indirectamente a todas las clases
> 'hermanas' :/

Lo entiendo, yo también me lo pienso varias veces antes de aplicar STI :D

> Tu idea está en nuestra cabeza claro.. lo que pasa que nos gustaría
> tener en una sola tabla todas las referencias e este tipo de objetos,
> que para hacerlo más claro se trata de referencias a ficheros en S3 y
> los hijos serían Photo, UserFile, Avatar, ...

Por curiosidad: ¿qué ventajas le veis? (aparte de tener menos tablas
en la base de datos, y por tanto en la cabeza?)

> La idea de usar mixins, includes, módulos y demás me parece un poco
> liosa y críptica, no sé, seguramente porque no estoy acostumbrado y
> todavía se me escapa de la cabeza... lo que me apetece es una
> implementación que la leas y la entiendas a la primera :/

Bueno, para quitarte un poco el miedo te animaría a que modelaras
cómoquedaría la cosa con un par de esas clases, por ejemplo Photo y
Avatar. A la hora de leerlo quizá tengas menos problemas de los que
crees, porque la distribución física del código es muy parecida a la
que tendrías si aplicaras herencia:

class S3
  # codigo comun

class Avatar < S3
  # codigo especifico

tendrías

module S3
  # codigo comun

class Avatar
  include S3
  # codigo especifico

No sé, ya te digo que en mi caso suelo preferir la flexibilidad de los
mixins a la herencia, y más si es un objeto AR porque quedas atado a
la STI... aunque todo depende del caso concreto, claro :)
6f952bee7570a3db2ecba5b06c0062b3?d=identicon&s=25 Fernando Guillen (fguillen)
on 2009-01-08 16:42
(Received via mailing list)
El día 8 de enero de 2009 16:39, alarkspur <alarkspur@gmail.com>
escribió:> Por si te sirve existe el plugin 
http://research.inplanb.com/has_ancestor

Gracias Aitor, tiene buena pinta, lo probaré en algún proyecto
experimental.. en el que estoy ahora no me atrevo bien sabes por qué
:), pero tiene pinta de conseguir muy bien lo que necesitaba.

f.
Fc3f12c165eaeac4999bc274215fb582?d=identicon&s=25 Roberto m. Oliva (roliva)
on 2009-01-08 16:43
(Received via mailing list)
Hola Fernando

Tienes toda la razon en lo que comentas, pero muchas veces lo mejor es
enemigo de lo bueno.
No te digo que STI es la panacea, pero es una buena solucion para muchos
de los casos de herencia.

"partiendo de la base de que estamos usando un motor de persistencia
precisamente porque preferimos la agilidad, la abstracción y la magia a
la optimización."

Date cuenta tambien que está el lado del propio desarrollador. Un
sistema STI tambien ayuda a que el codigo sea mas sencillo con lo bien
que esta integrado en Rails.
Si tan poco te preocupa el rendimiento de la aplicación es por que vas a
desarrollar muy rapidamente. Eso tambien es paradojico entre usar STI o
un plugin de terceros para implementar MTI (por ejemplo).

Vamos, en definitiva, lo correcto es lo que estás haciendo: sopesar los
pros y los contras pero, en mi opinion, STI no es tan malo como parece.

Un saludo
Roberto


Fernando Guillen
escribió:> El día 8 de enero de 2009 13:42, Roberto M. Oliva 
<roliva@idecnet.com> escribió:
>
6f952bee7570a3db2ecba5b06c0062b3?d=identicon&s=25 Fernando Guillen (fguillen)
on 2009-01-08 16:48
(Received via mailing list)
El día 8 de enero de 2009 16:41, Raul Murciano <raul@murciano.net>
escribió:>
>> Tu idea está en nuestra cabeza claro.. lo que pasa que nos gustaría
>> tener en una sola tabla todas las referencias e este tipo de objetos,
>> que para hacerlo más claro se trata de referencias a ficheros en S3 y
>> los hijos serían Photo, UserFile, Avatar, ...
>
> Por curiosidad: ¿qué ventajas le veis? (aparte de tener menos tablas
> en la base de datos, y por tanto en la cabeza?)

Pues la verdad cada vez le veo menos ventajas :).. no sé..

>
>> La idea de usar mixins, includes, módulos y demás me parece un poco
>> liosa y críptica, no sé, seguramente porque no estoy acostumbrado y
>> todavía se me escapa de la cabeza... lo que me apetece es una
>> implementación que la leas y la entiendas a la primera :/
>
> Bueno, para quitarte un poco el miedo te animaría a que modelaras cómo
> quedaría la cosa con un par de esas clases, por ejemplo Photo y
> Avatar. A la hora de leerlo quizá tengas menos problemas de los que
> crees, porque la distribución física del código es muy parecida a la
> que tendrías si aplicaras herencia:

jaja.. muchas gracias Raúl.. la verdad que ayuda mucho ver como lo
explicas.. lo tendré en cuenta.
>
> No sé, ya te digo que en mi caso suelo preferir la flexibilidad de los
> mixins a la herencia, y más si es un objeto AR porque quedas atado a
> la STI... aunque todo depende del caso concreto, claro :)

Gracias .

f.
6f952bee7570a3db2ecba5b06c0062b3?d=identicon&s=25 Fernando Guillen (fguillen)
on 2009-01-08 16:54
(Received via mailing list)
El día 8 de enero de 2009 16:43, Roberto M. Oliva <roliva@idecnet.com>
escribió:> Hola Fernando
>
> muchas veces lo mejor es
> enemigo de lo bueno.

Tienes razón es éste y los posteriores comentarios..

f.
39086eb3d9a1437276d07c08ea0c3821?d=identicon&s=25 Guillermo Álvarez Fernández (Guest)
on 2009-01-08 17:48
(Received via mailing list)
El 08/01/2009, a las 16:18, Fernando Guillen escribió:
> Tu idea está en nuestra cabeza claro.. lo que pasa que nos gustaría
> tener en una sola tabla todas las referencias e este tipo de objetos,
> que para hacerlo más claro se trata de referencias a ficheros en S3 y
> los hijos serían Photo, UserFile, Avatar, ...

A ver empezado por el problema concreto leches. Así es más fácil opinar.

La pregunta correcta sería si los campos que son diferentes han de ser
indexados (bien sea sphinx/indices mysql). De no ser así STI es la
mejor opción con las propiedades serializadas y un campo text a toda
la base.

Si ha de ser indexado tiraría yo por polimorfismo, dejando en la tabla
File los campos relacionados con el fichero y los metodos de
interacción con s3, un destroy debería borrar la fila y el archivo
remoto de s3.

En ambos casos haría delegación de method_missing a la asociación
polimórfica (en caso de usar polimorfismo).

f =  File.first # <File>
f.file_name # 'foto.jpg'
f.mime # 'image/jpeg2000.99'
f.read # <Photo> #implementación rara de usar read pero el nombre del
metodo podría ser otro.
f.read.camera_info # 'Foto hecha con un iphone mas'
f.camera_info # 'Foto hecha con un iphone mas' # delegate


p = Photo.first
p.camera_info # 'Foto hecha un iphone mas'
p.file_name # 'foto.jpg' # Delegación inversa

Es como se me ocurre así a bote pronto.

Un Saludo
F625b891618be8ec32547a07b3192bb0?d=identicon&s=25 Francesc Esplugas (fesplugas)
on 2009-01-08 17:58
(Received via mailing list)
Quizas he hecho una lectura un poco transversal, pero si lo que
quieres es tener varios ficheros adjuntos a un modelo, no te serviria
Paperclip? Nosotros lo utilizamos juntamemte con relaciones
polimorficas para solucionar un problema parecido al tuyo.

On 08/01/2009, at 17:47, Guillermo Álvarez Fernández
<guillermo@cientifico.n
6f952bee7570a3db2ecba5b06c0062b3?d=identicon&s=25 Fernando Guillen (fguillen)
on 2009-01-08 18:05
(Received via mailing list)
El día 8 de enero de 2009 17:57, Francesc Esplugas
<francesc.esplugas@gmail.com>
escribió:>
> Quizas he hecho una lectura un poco transversal, pero si lo que
> quieres es tener varios ficheros adjuntos a un modelo, no te serviria
> Paperclip? Nosotros lo utilizamos juntamemte con relaciones
> polimorficas para solucionar un problema parecido al tuyo.

jaja.. Francesc.. sí un poco transversal si ..

Saludete
f.
This topic is locked and can not be replied to.