Sobrecargar modelos, controladores, vistas

En la reunión de Rails de Barcelona del pasado martes, estuvimos
hablando de re-aprovechar codigo de nuestras aplicaciones para poder
tener algo parecido a un “core”.

La idea es tener un plugin que nos de una funcionalidad como por
ejemplo una red social, una sistema de tiendas online … etc. Hasta
aquí todo correcto, porque de la aplicación actual se puede extraer el
plugin con relativa facilidad.

El problema esta cuando hay algo del plugin que necesitamos modificar,
una vista, un método … La idea seria sobre-escribir o extender parte
del plugin desde nuestra aplicación Rails.

Si tenemos un modelo llamado User en el plugin y en nuestra aplicación
ya tenemos definido un modelo User, cual de los dos se usa? El de
nuestra
aplicación.
Existen los engines, un plugin llamado desert [1] que solucionan esta
problemática, pero son bastante grandes y no creo que sea buena idea
depender de plugins tan grandes en una
aplicación.
Con el plugin Typus [2] solucione la extensión de templates, de rutas
y de controladores, pero no la de los modelos.

¿Alguien se ha encontrado con alguna problemática similar?

La idea al final seria tener algo como …

plugin

     class Page < ActiveRecord::Base
       validates_presence_of :title
def permalink
         id
       end
     end

application

     class Page < ActiveRecord::Base
  def permalink
         title.downcase
end

end

Y que al final desde nuestra aplicacion sobreescribieramos el metodo
permalink.

[1] http://github.com/pivotal/desert
[2] http://github.com/fesplugas/typus

2008/7/4 Francesc E. [email protected]:

Si tenemos un modelo llamado User en el plugin y en nuestra aplicación
ya tenemos definido un modelo User, cual de los dos se usa? El de
nuestra aplicación.

En realidad depende del orden en el que se lean las definiciones,
podria pasar que se hiciera un require del modelo del plugin en el
proceso de arranque (y en tal caso habria que hacerlo del modelo de la
aplicacion host porque ya no saltaria const_missing).

Desert me parece que modifica dependencies.rb para automatizar esa
triquiñuela: dado un const_missing User la redefinicion de
dependencies.rb basicamente busca todos los user.rb en un cierto orden
y los carga, de modo que el de la aplicacion reabre la clase definida
anteriormente por el plugin.

A mi me parece la mejor aproximacion, ya que el plugin core necesita
usar la clase User, y seria deseable que la aplicacion pueda disponer
de la clase User misma tambien. Si la aplicacion por ejemplo tuviera
que heredar de MiCore::User entonces el plugin por lo general no
sabria nada de la clase de la aplicacion.

Solo veo un gotcha que es que para reabrir la clase el padre debe ser
el mismo, de manera que la jerarquia en el core obliga a una jerarquia
en la aplicacion. Por ejemplo el User del core no puede ser hijo de
AR::Base y el de la aplicacion de UserAbstract. Pero es una
restriccion razonable para lo que se obtiene.

Si el plugin desert es demasiado habria que definir que subconjunto de
funcionalidad se necesita, pero alguna tecnica de ese tipo tendrias
que emplear porque sabes que las constantes estan en un espacio de
nombres global, que en Rails es esperado tirar de la auto carga de
modelos via const_missing, y blah blah.