Rails es un framework de desarrollo web que implementa el patrón Modelo - Vista - Controlador, esto es, establece unas normas y unos formatos para que no mezclemos lo referente al modelo de datos de la lógica de la aplicación y de las vistas o presentación.
Algunas de las ventajas del patrón MVC son (que seguro las sabéis):
- código más limpio: el ejemplo más claro es no encontrarse en las vistas consultas a base de datos
- orden: si queremos modificar una vista vamos a la carpeta
views, si queremos modificar un controlador al fichero correspondiente de la carpetacontrollers, etcétera - más DRY y menos código: todo esto produce que escribamos las cosas una sola vez, lo que permite reducir el número de líneas de código y, por tanto, el número de errores en ellas
Hasta ahora habían aparecido entornos que intentaban implementar este patrón, pero no siempre quedando el código de la manera más limpia posible, quedándose en pseudo implementaciones que comenzaron a llamarse de 2 capas o de 2 capas y media.
Rails sin embargo, gracias a su sistema de convenciones, te permite seguir casi a rajatabla este patrón (por supuesto que te da la libertad para no hacerlo y mezclarlo todo en una capa, al más puro estilo PHP básico), lo cuál, a su vez, te permite modificar tu paradigma de programación y tener siempre presente la separación en tres capas para factorizar y reestructurar el código. Este hecho es comunmente conocido entre los desarrolladores de Rails como "nunca mi código va a ser perfecto".
Pero volviendo al tema que nos atañe, que no es más que una pequeña (o no tan pequeña) cuestión que se planteó hace unos días en la lista del core de Rails acerca de si tiene sentido que los helpers estén orientados al modelo de datos, o de cómo hay una ligadura intrínseca entre el modelo de datos y ciertas partes de la presentación. El hilo en cuestión se llama Object Oriented Helpers.
Pero antes de entrar en materia, veamos primero un ejemplo real de La Coctelera: en la vista de un post se introduce un código en RDF para el funcionamiento de los trackbacks, algo tal que así:
Esto se podría incluir perfectamente en un helper del controlador posts quedando la vista así:
<%= trackback_code(@post) %>
Hasta aquí todo bien, ¿pero qué pasa si tenemos varios tipos de posts? Si queremos reutilizar el mismo helper (que va a ser que sí, porque somos chicos DRY) tendríamos que incluir unos feos condicionales del estilo:
if post.class == Post ... elsif post.class == Pagepost ... end
Es decir, que tendríamos un código bastante más sucio (pero muy DRY, eso sí).
La otra opción sería definir el helper para la clase Post y para la clase Pagepost, con el inconveniente que, dos métodos que hacen los mismo, pero que son específicos de una clase o de otra, deben de tener distinto nombre, con la pequeña sobrecarga de esfuerzo mental que esto puede requerir:
<%= trackback_code_posts(@post) %>
<%= trackback_code_pagepost(@pagepost) %>
Viendo este código (bueno, este exactamente no, pero sé que me entendéis) alguien pensó que eso no es más que un helper dependiente del modelo (de la clase) y que se podría reescribir de la siguiente manera:
<%= @post.trackback_code %>
<%= @pagepost.trackback_code %>
A pesar de que la sintaxis es ideal, es una pequeña atrocidad y una lástima, pero estamos incluyendo parte de la presentación en el modelo de datos (al contrario de como se hacía en PHP, vaya), lo cuál es malo porque:
- no es su lugar
- un modelo debe ser independiente de su representación: pensad que podemos querer ver un post en un feed, en nuestro navegador web o en texto plano
- cuando queramos modificar algo de la presentación ya tendríamos dos lugares en donde buscar: el modelo y la vista asociada
Sin embargo sí que resulta bastante interesante y se puede plantear de tal forma que dinámicamente se carguen helpers como métodos del modelo, vía un mixin, con lo cuál:
- no hay presentación en el modelo de datos
- se puede utilizar la sintaxis que arriba os he puesto
Y la forma de implementarla no está clara, pero se dan algunas pinceladas en el hilo del que os he hablado antes. En primer lugar existe un patrón que se llama Presetation Model que sirve justamente para esto. Además, en el propio hilo se enlaza un post titulado Rails Model View Controller + Presenter? que explica justamente cómo implementar un Presenter en Rails.
En segundo lugar, David, en su intervención en la Conferencia Rails Hispana nombró algo sobre Presenters, sin embargo he estado buscando entre el código de la 1.2 y no he encontrado nada. No sé si se refería entonces a Rails 2.0 o lo nombró de pasada como una nueva feature que han desarrollado para la próxima aplicación que lanzarán en 37 signals (el famoso CRM), así que aquí pido el comodín del público, y si alguien sabe algo o recuerda algo más, que por favor lo diga en los comentarios.
Conclusión
La conclusión es que no hay conclusión y que es un tema abierto y que va a estar activo los próximos meses: por un lado parece que a los miembros del core no les termina de convencer su uso, o que por lo menos es un asunto que quieren meditar más. Si al final se deciden parece que no va a ser en la inminente versión 1.2, sino que será para más adelante.
También parece que están formalizando un plugin, que está aún muy verde, sin documentación ni tests, y que además puede que rehagan de cero. Puede ser el primer paso para experimentar con este nuevo planteamiento.
¿Vosotros qué pensáis?
Por cierto, querido lector fiel que has llegado hasta el final: ¡Feliz Año!
%=>%=>%=>%=>%=>
Feliz año nuevo mozuelo!
Pues hombre, a mi me parece que estamos hablando de casos muy concretos. Todavía hay mucha gente que viene de lenguajes donde las capas MVC no están tan separadas y les resulta muy complicado dejar todo puesto en su sitio.
Todos hemos sido víctimas de meter demasiada lógica en la vista.
Por tanto mi posición es que si implementando este método al final cada cosita queda donde tiene que estar tal vez haya merecido la pena la vuelta.
Aunque hay que reconocer que es un rato larga la vuelta :D
Creo que una posible solución para el primer acercamiento sería utilizar el 'factory pattern', es decir, una clase que se encargase de devolver el helper necesario en función de un parámetro por ejemplo para así tener todo más 'modularizado' y para evitar el engorro de los if .. else .., utilizar el 'hashed adapter', se trata solamente de guardar las instancias o clases en un hash y así tienes el acceso directo al objeto/clase (igual el ejemplo no es del todo acertado, pero todavía estoy bastante verde con ruby):
---
class Foo
def test
"FOO"
end
end
class Bar
def test
"BAR"
end
end
class Factory
@@instances = {Foo => Foo.new, Bar => Bar.new}
def Factory.get_class(class_name)
@@instances[class_name].test
end
end
puts Factory.get_class(Foo)
puts Factory.get_class(Bar)
---
a lo mejor ni siquiera sería necesario esta segunda parte ya que podriamos obtener la clase/instancia de manera dinámica .
Aupa!
Dagi3d, no creo que el problema esté en cómo implementarlo, que a mi entender los miembros del core seguro que saben muy bien cómo hacerlo, sino si es correcto hacerlo desde un punto de vista conceptual.
Desde luego a mí no me termina de gustar tampoco la idea de mezclar las funciones de los modelos y vistas. El hecho de que con un mixin los métodos del helper se junten con los propios del modelo permite que el código sea muy limpio pero a costa de tratarlo exactamente igual que a un campo del modelo. Esto no facilita la tarea de saber que-es-lo-que-es lo que hay por detrás sino todo lo contrario. Ahora:
@post.metodo_la_mar_de_chulo
puede estar en tres sitios: el helper, el modelo o cómo campo en la bbdd (ya se que es un nombre muy raro para un campo, pero cosas peores se han visto).
No sé si en algún caso puede llegar a tener sentido (en el que pones desde luego no lo veo, la función del helper puede recibir lo que sea y tener dentro esos condicionales tan feos como imprescindibles en cualquier lenguaje) pero compañeros a mí esto no me termina de gustar mucho.
Salu2
[ah! y aunque un pelín tarde] ¡F3LIZ 4Ñ0!
Interesante tema que, por cierto, sigue vivo el la lista del core de Rails. En uno de los últimos hilos han anunciado un nuevo plugin, implementación del patrón presenter que tiene buena pinta:
http://simply_presentable.richcollins.net/
Estoy de acuerdo en que el tema de la implementación puede ser más o menos secundario (con un lenguaje como Ruby estos chicos del core pueden hacer maravillas). La cuestión en cuanto al uso o no del patrón presenter pasa por decidir si se quiere añadir una capa de abstracción más, abandonando la simplicidad de la implementación actual del MVC en Rails.