Diseño OO en Rails: dónde poner cosas
Realmente disfruto Rails (aunque generalmente no tengo REST), y disfruto que Ruby sea muy OO. Aun así, la tendencia a crear subclases ActiveRecord enormes y controladores enormes es bastante natural (incluso si utiliza un controlador por recurso). Si tuvieras que crear mundos de objetos más profundos, ¿dónde colocarías las clases (y los módulos, supongo)? Estoy preguntando sobre vistas (¿en los propios Ayudantes?), controladores y modelos.
Lib está bien y encontré algunas soluciones para que se recargue en un entorno de desarrollo , pero me gustaría saber si hay una mejor manera de hacer esto. Realmente me preocupa que las clases crezcan demasiado. Además, ¿qué pasa con los motores y cómo encajan?
Debido a que Rails proporciona estructura en términos de MVC, es natural terminar usando solo los contenedores de modelo, vista y controlador que se le proporcionan. El modismo típico para principiantes (e incluso algunos programadores intermedios) es meter toda la lógica de la aplicación en el modelo (clase de base de datos), controlador o vista.
En algún momento, alguien señala el paradigma del "modelo gordo, controlador delgado", y los desarrolladores intermedios eliminan apresuradamente todo de sus controladores y lo arrojan al modelo, que comienza a convertirse en un nuevo bote de basura para la lógica de la aplicación.
Los controladores delgados son, de hecho, una buena idea, pero el corolario: poner todo en el modelo no es realmente el mejor plan.
En Ruby, tienes un par de buenas opciones para hacer las cosas más modulares. Una respuesta bastante popular es simplemente usar módulos (generalmente escondidos en lib
) que contengan grupos de métodos y luego incluir los módulos en las clases apropiadas. Esto ayuda en los casos en los que tiene categorías de funcionalidad que desea reutilizar en varias clases, pero donde la funcionalidad todavía está teóricamente adjunta a las clases.
Recuerde, cuando incluye un módulo en una clase, los métodos se convierten en métodos de instancia de la clase, por lo que aún terminará con una clase que contiene una gran cantidad de métodos, pero están muy bien organizados en varios archivos.
Esta solución puede funcionar bien en algunos casos; en otros casos, querrás pensar en usar clases en tu código que no sean modelos, vistas o controladores.
Una buena forma de pensarlo es el "principio de responsabilidad única", que dice que una clase debe ser responsable de una sola (o una pequeña cantidad) de cosas. Sus modelos son responsables de conservar los datos de su aplicación en la base de datos. Sus controladores son responsables de recibir una solicitud y devolver una respuesta viable.
Si tiene conceptos que no encajan perfectamente en esos cuadros (persistencia, gestión de solicitudes/respuestas), probablemente quiera pensar en cómo modelaría la idea en cuestión. Puede almacenar clases que no sean de modelo en app/classes, o en cualquier otro lugar, y agregar ese directorio a su ruta de carga haciendo:
config.load_paths << File.join(Rails.root, "app", "classes")
Si estás usando pasajero o JRuby, probablemente también quieras agregar tu ruta a las rutas de carga ansiosas:
config.eager_load_paths << File.join(Rails.root, "app", "classes")
La conclusión es que una vez que llegas a un punto en Rails en el que te encuentras haciendo esta pregunta, es hora de reforzar tus habilidades en Ruby y comenzar a modelar clases que no sean solo las clases MVC que Rails te ofrece de forma predeterminada.
Actualización: esta respuesta se aplica a Rails 2.x y superiores.
Actualización : Se ha confirmado el uso de Concerns como el nuevo valor predeterminado en Rails 4 .
Realmente depende de la naturaleza del módulo en sí. Normalmente coloco las extensiones de controlador/modelo en una carpeta /concerns dentro de la aplicación.
# concerns/authentication.rb
module Authentication
...
end
# controllers/application_controller.rb
class ApplicationController
include Authentication
end
# concerns/configurable.rb
module Configurable
...
end
class Model
include Indexable
end
# controllers/foo_controller.rb
class FooController < ApplicationController
include Indexable
end
# controllers/bar_controller.rb
class BarController < ApplicationController
include Indexable
end
/lib es mi opción preferida para bibliotecas de uso general. Siempre tengo un espacio de nombres de proyecto en lib donde coloco todas las bibliotecas específicas de la aplicación.
/lib/myapp.rb
module MyApp
VERSION = ...
end
/lib/myapp/CacheKey.rb
/lib/myapp/somecustomlib.rb
Las extensiones principales de Ruby/Rails generalmente tienen lugar en los inicializadores de configuración, de modo que las bibliotecas solo se cargan una vez en Rails boostrap.
/config/initializer/config.rb
/config/initializer/core_ext/string.rb
/config/initializer/core_ext/array.rb
Para fragmentos de código reutilizables, a menudo creo (micro)complementos para poder reutilizarlos en otros proyectos.
Los archivos auxiliares generalmente contienen métodos auxiliares y, a veces, clases cuando el objeto está destinado a ser utilizado por auxiliares (por ejemplo, creadores de formularios).
Esta es una descripción general realmente general. Proporcione más detalles sobre ejemplos específicos si desea obtener sugerencias más personalizadas. :)