2009/12/4 Luis Galnares <
lgal...@gmail.com>:
> Hola
>
> Les pido su opinion sobre lo siguiente. De repente es medio básico pero
> bueno, son mis primeros pasos
>
> En mi aplicacion tengo una clase X de la que heredan 4 subclases A,B,C,D.
> - La clase X no se instanciaría nunca, es una clase abstracta
> - A,B,C,D comparten la mayoría de los atributos por eso los heredan de X
>
> En varios sitios vi que en ese caso recomiendan implementar esto con STI
> (single table inheritance), o sea tener una sola tabla para todas las
> subclases en lugar de tener una tabla para cada subclase.
>
> Supongo que eso tiene alguna ventaja pero en realidad no entiendo bien
> porqué ya que el manejo de la base de datos es transparente de todas formas
> cual es la ventaja que puedo tener?
La ventaja es que es la forma de heredar sin que AR se rompa. La
herencia, en ActiveRecord, está atada inexorablemente a STI, y
cualquier intento de hacer otra cosa requiere multiples hacks :)
> Ademas me compica lo siguiente:
> - El tema del controller y las views. Es decir quiero que todas las
> subclases usen el mismo index pero distindo edit
> - Que las views de cada subclass sean lo mas DRY posible
Herencia de controllers :)
Ponele que tus modelos fueran Assets, y las subclases que tenés son
Video, Image, Text.
Tendrías un AssetsController, y después VideosController,
ImagesController, y TextsController, y estos tres heredarían de
AssetsController.
Las rutas serían algo así:
map.resources :assets, :only => [:index, :destroy]
map.with_options :only => [:show, :edit, :update] do |asset|
asset.resources :videos
asset.resources :images
asset.resources :texts
end
En dónde van el :new y el :create va a depender de cuán similares sean
entre ellas las vistas, ponele que para este caso capaz que todos los
assets para crearlos simplemente tienen un file field, un nombre y una
descripción, y después lo separo como Video, Image o Text según el
content_type, entonces ahí el :new y :create irían en el
AssetsController, porque el usuario está, efectivamente, creando un
Asset sin importarle qué es.
Luego para las vistas, tu assets/index.html.erb tendría algo como esto:
<ul>
<%= render @assets %>
</ul>
Rails (2.3 y superior, la sintáxis es un poco más verbosa para
versiones más viejas) va a buscar un partial para cada elemento,
fijándose en el nombre de la clase del objeto, por lo que para que eso
funcione tenés que escribir partials para cada una de tus subclases:
videos/_video.html.erb, images/_image.html.erb y texts/_text.html.erb
que contengan el <li> con lo que vayas a mostrar adentro (o una tabla
en el index y los partials implementan los <tr>, se entiende la idea)
Después para las otras vistas cada controller implementa las suyas y
no te importa tanto.
Lo único que queda es ver qué pasa con los helpers para generar los
links. Si para cada asset tenés que hacer video_path(asset), o
image_paht(asset), o text_path(asset), obviamente va a quedar feísimo
y lleno de ifs en las vistas.
Para esto rails tiene lo que le llama "polymorphic url for". Vos
simplemente proveés un objeto, y rails adivina según el tipo de objeto
qué querés. Entonces, tus links al "show" de cada objeto serían <%=
link_to
asset.name, asset %>. Y eso va a interpretarse como
video_path(asset) si asset.is_a?(Video), image_path(asset) si
asset.is_a?(Image), etc.
Cuando querés urls con más "partes" en el helper, le pasás un array:
[:edit, asset] se va a interpretar como edit_video_path(asset), etc
etc.
Cualquier duda preguntá!
-foca