Modelo de rieles, vista, controlador y ayudante: ¿qué va a dónde?

155

En Ruby on Rails Development (o MVC en general), qué regla rápida debo seguir en cuanto a dónde poner la lógica.

Responda afirmativamente: con Do ponga esto aquí , en lugar de No ponga eso allí .

theschmitzer
fuente

Respuestas:

173

MVC

Controlador : ponga aquí el código que tiene que ver con calcular lo que un usuario quiere y decidir qué darles, determinar si están conectados, si deberían ver ciertos datos, etc. Al final, el controlador examina las solicitudes y calcula qué datos (Modelos) mostrar y qué Vistas representar. Si tiene dudas sobre si el código debe ir en el controlador, entonces probablemente no debería. Mantenga sus controladores flacos .

Vista : La vista solo debe contener el código mínimo para mostrar sus datos (Modelo), no debe procesar o calcular mucho, debe mostrar datos calculados (o resumidos) por el Modelo o generados desde el Controlador. Si su Vista realmente necesita hacer un procesamiento que no puede hacer el Modelo o el Controlador, coloque el código en un Ayudante. Una gran cantidad de código Ruby en una vista hace que el marcado de las páginas sea difícil de leer.

Modelo : su modelo debe ser donde reside todo el código que se relaciona con sus datos (las entidades que componen su sitio, por ejemplo, usuarios, publicaciones, cuentas, amigos, etc.). Si el código necesita guardar, actualizar o resumir datos relacionados con sus entidades, póngalo aquí. Será reutilizable en sus Vistas y Controladores.

pauliephonic
fuente
2
La gente comienza a alejarse del modelo gordo. Me gusta pensar en mi modelo como una estructura de datos. Luego escribo un objeto Ruby que implementa el comportamiento, inicializándolo con el modelo (trata el modelo como sus datos de la misma manera que trataría las cadenas y matrices como datos en objetos fuera de Rails). Aquí hay un buen video con un ejemplo de esta técnica.
Joshua Cheek
@AdamDonahue No estoy seguro de que algo gordo pueda ser visto como algo bueno. Toneladas de responsabilidades son mejores pertenecer a los servicios.
fatuhoku
35

Para agregar a la respuesta de pauliephonic:

Ayudante : funciones para facilitar la creación de la vista. Por ejemplo, si siempre está iterando sobre una lista de widgets para mostrar su precio, póngalo en un asistente (junto con un parcial para la visualización real). O si tiene un trozo de RJS que no desea saturar la vista, póngalo en una ayuda.

jcoby
fuente
En realidad, ¿no ponemos también el método sign_in en Helper? Como sugirió el Tutorial RoR aquí >>> ruby.railstutorial.org/book/…
Ivan Wang
14

El patrón MVC en realidad solo tiene que ver con la interfaz de usuario y nada más. No debe colocar ninguna lógica empresarial compleja en el controlador, ya que controla la vista, pero no la lógica. El Controlador debe ocuparse de seleccionar la vista adecuada y delegar cosas más complejas al modelo de dominio (Modelo) o la capa empresarial.

El diseño impulsado por dominio tiene un concepto de servicios, que es un lugar en el que pega la lógica que necesita orquestar varios tipos diferentes de objetos, lo que generalmente significa lógica que no pertenece naturalmente a una clase de modelo.

Generalmente pienso en la capa de Servicio como la API de mis aplicaciones. Mis capas de Servicios generalmente se ajustan bastante a los requisitos de la aplicación que estoy creando, por lo tanto, la capa de Servicio actúa como una simplificación de las interacciones más complejas que se encuentran en los niveles inferiores de mi aplicación, es decir, podría lograr el mismo objetivo sin pasar por las capas de Servicio pero tendrías que tirar de muchas más palancas para que funcione.

Tenga en cuenta que no estoy hablando de Rails aquí, estoy hablando de un estilo arquitectónico general que aborda su problema particular.

Søren Spelling Lund
fuente
Esta es una gran respuesta :)
Carlos Martinez
7

Ponga cosas relacionadas con la autorización / control de acceso en el controlador.

Los modelos tienen que ver con sus datos. Validación, Relaciones, CRUD, Lógica Empresarial

Las vistas tratan de mostrar sus datos. Mostrar y obtener solo entrada.

Los controladores tratan de controlar qué datos van de su modelo a su vista (y qué vista) y de su vista a su modelo. Los controladores también pueden existir sin modelos.

Me gusta pensar en el controlador como un guardia de seguridad / recepcionista que le dirige al cliente (solicitud) al mostrador apropiado donde le hace una pregunta al cajero (ver). El cajero (vista) luego va y obtiene la respuesta de un gerente (modelo), a quien nunca ve. Luego, solicite que regrese al guardia de seguridad / recepcionista (controlador) y espere hasta que se le indique que vaya a otro cajero (vista) que le diga la respuesta que el gerente (modelo) les dijo en respuesta a la pregunta del otro cajero (vista) .

Del mismo modo, si desea decirle al cajero (ver) algo, entonces sucede lo mismo, excepto que el segundo cajero le dirá si el gerente aceptó su información. También es posible que el guardia de seguridad / recepcionista (controlador) le haya dicho que haga una caminata ya que no estaba autorizado a comunicarle esa información al gerente.

Entonces, para extender la metáfora, en mi mundo estereotipado y poco realista, los cajeros (puntos de vista) son bonitos pero con la cabeza vacía y a menudo creen todo lo que les dices, los guardias de seguridad / recepcionistas son mínimamente educados pero no están muy bien informados, pero saben dónde la gente debería y No debería ir y los gerentes son realmente feos y malos, pero saben todo y pueden decir qué es verdad y qué no.

srboisvert
fuente
4

Una cosa que ayuda a separar adecuadamente es evitar el anti-patrón "pasar variables locales del controlador para ver". En lugar de esto:

# app/controllers/foos_controller.rb:
class FoosController < ApplicationController

  def show
    @foo = Foo.find(...)
  end

end

#app/views/foos/show.html.erb:
...
<%= @foo.bar %>
...

Intenta moverlo a un getter que esté disponible como método auxiliar:

# app/controllers/foos_controller.rb:
class FoosController < ApplicationController

  helper_method :foo

  def show
  end

  protected

  def foo
    @foo ||= Foo.find(...)
  end

end

#app/views/foos/show.html.erb:
...
<%= foo.bar %>
...

Esto facilita la modificación de lo que se pone en "@foo" y cómo se usa. Aumenta la separación entre el controlador y la vista sin hacerlos más complicados.

James A. Rosen
fuente
uhmmm ... Yuk. ¿Puede agregar algunas buenas razones / escenarios para cuándo haría esto? Esto rompe KISS y YAGNI y es muy maloliente (solo para
agregar
2
1) Rails hace mucha magia para copiar las variables de instancia del controlador a su instancia de vista. 2) La implementación sugerida también solo carga foo si se accede a ella, lo que puede ahorrar algo de trabajo parte del tiempo. Sin embargo, la respuesta importante es realmente 1).
webmat
11
Suspiro Esto es terrible. El uso compartido de variables de instancia de Rails es una característica, no un antipatrón. Es un azúcar sintáctico omnipresente y de bajo gasto mental que rara vez o nunca causa problemas en el mundo real. Si no te gusta, está bien, pero codificarlo con una estructura barroca no estándar empeora las cosas infinitamente. En este caso, efectivamente está haciendo foo una variable global (por controlador de todos modos). Intentar corregir un abuso percibido del alcance variable al aumentar drásticamente el alcance es extremadamente irónico.
gtd
1
No lo estoy comprando, dasil003. El alcance de fooy de @fooson los mismos: ambos tienen un alcance para el par <ControllerClass, request>. Además, al usar la versión getter, puedo cambiar cómo Foose encuentra / almacena / almacena en caché ese objeto sin cambiar la forma en que la vista accede a él.
James A. Rosen
1
Creo que te refieres al antipatrón de "pasar variables de instancia". Una instancia var perderá el estado de todo el renderizado, incluso en parciales profundamente anidados. Su solución también tiene fugas de estado, pero es ligeramente mejor que una instancia var porque no permite la reasignación. Pasar un local es realmente lo mejor porque es como llamar a un método; lo local no puede ser visto por parciales. Mira esta respuesta .
Kelvin
2

Bueno, de alguna manera depende de con qué tiene que lidiar la lógica ...

A menudo, tiene sentido introducir más cosas en sus modelos, dejando pequeños controladores. Esto garantiza que esta lógica se pueda usar fácilmente desde cualquier lugar donde necesite acceder a los datos que representa su modelo. Las vistas casi no deben contener lógica. Así que realmente, en general, debes esforzarte para que no te repitas.

Además, un poco de google revela algunos ejemplos más concretos de lo que va a dónde.

Modelo: requisitos de validación, relaciones de datos, métodos de creación, métodos de actualización, métodos de destrucción, métodos de búsqueda (tenga en cuenta que no solo debe tener las versiones genéricas de estos métodos, sino que si hay algo que está haciendo mucho, como encontrar personas con rojo cabello por apellido, entonces debes extraer esa lógica para que todo lo que tienes que hacer es llamar al find_redH_by_name ("smith") o algo así)

Vista: Esto debería ser todo sobre el formato de datos, no el procesamiento de datos.

Controlador: Aquí es donde va el procesamiento de datos. Desde Internet: "El propósito del controlador es responder a la acción solicitada por el usuario, tomar cualquier parámetro que el usuario haya establecido, procesar los datos, interactuar con el modelo y luego pasar los datos solicitados, en forma final, a ver."

Espero que ayude.

Paul Wicks
fuente
0

En términos simples, en general, los Modelos tendrán todos los códigos relacionados con la (s) tabla (s), sus relaciones simples o complejas (piense en ellas como consultas sql que involucran múltiples tablas), manipulación de los datos / variables para llegar a un resultado utilizando la lógica de negocios .

Los controladores tendrán códigos / punteros hacia los modelos relevantes para el trabajo solicitado.

Las vistas aceptarán la entrada / interacción del usuario y mostrarán la respuesta resultante.

Cualquier desviación importante de estos generará una tensión no deseada en esa parte y el rendimiento general de la aplicación puede verse afectado.

Anutosh
fuente
-1

Pruebas, pruebas ... Ponga tanta lógica como sea posible en el modelo y luego podrá probarlo correctamente. Las pruebas unitarias prueban los datos y la forma en que se forman al probar el modelo, y las pruebas funcionales prueban la forma en que se enrutan o controlan al probar los controladores, por lo que se deduce que no puede probar la integridad de los datos a menos que estén en el modelo.

j


fuente