2009-11-07 13 views
5

Tengo una aplicación que modela una casa. La casa tiene_muchas habitaciones, habitaciones tiene_muchas luces y pequeños electrodomésticos, etc. También tengo un controlador llamado Calculadora que es cómo se accede a la aplicación. Los datos se agregan a la casa (y sus habitaciones) usando el controlador de la Calculadora. Luego se genera un informe, que se encuentra en app/views/calculator/report.html.erb.¿Dónde debería ir la lógica de cálculo en una aplicación de Rails?

Mi pregunta es ¿a dónde deben llegar todos los cálculos y la lógica del informe? Actualmente lo tengo todo en la vista, con algunas cosas en calculator_helper. Normalmente esto iría en el modelo, ¿verdad? Pero la calculadora no tiene un modelo que se generó. ¿Cuál es el estándar para esto?

Aquí está el controlador de la calculadora.

class CalculatorController < ApplicationController 
    def index 
    end 

    def save_house 
    @house = House.new(params[:house]) 
    respond_to do |format| 
     if @house.save 
     format.html { render :action => 'add_rooms', :id => @house } 
     format.xml { render :xml => @house, :status => :created, :location => @house } 
     else 
     format.html { render :action => 'index' } 
     format.xml { render :xml => @house.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

    def add_rooms 
    @house = House.find(params[:id]) 
    @rooms = Room.find_by_house_id(@house.id) 

    rescue ActiveRecord::RecordNotFound 
    logger.error("Attempt to access invalid house #{params[:id]}") 
    flash[:notice] = "You must create a house before adding rooms" 
    redirect_to :action => 'index' 
    end 

    def add_room 
    @room = Room.new(params[:room]) 
    @house = @room.house 

    respond_to do |format| 
     if @room.save 
     flash[:notice] = "Room \"#{@room.name}\" was successfully added." 
     format.html { render :action => 'add_rooms' } 
     format.xml { render :xml => @room, :status => :created, :location => @room } 
     else 
     format.html { render :action => 'add_rooms' } 
     format.xml { render :xml => @room.errors, :status => :unprocessable_entity } 
     end 
    end 
    rescue ActiveRecord::RecordNotFound 
    logger.error("Attempt to access invalid house #{params[:id]}") 
    flash[:notice] = "You must create a house before adding a room" 
    redirect_to :action => 'index' 
    end 

    def report 
    flash[:notice] = nil 
    @house = House.find(params[:id]) 
    @rooms = Room.find_by_house_id(@house.id) 
    rescue ActiveRecord::RecordNotFound 
    logger.error("Attempt to access invalid house #{params[:id]}") 
    flash[:notice] = "You must create a house before generating a report" 
    redirect_to :action => 'index' 
    end 
end 
+0

Por favor, muéstrenos su clase de calculadora. –

+0

Me gusta la respuesta de James. Otra pregunta que creo que debería hacerse es por qué está abandonando la convención: ¿por qué el controlador de la calculadora maneja cosas que aparentemente pertenecen al controlador de la casa? No digo que lo estés haciendo mal, solo digo que vale la pena pensarlo un poco más. –

+0

Buen punto, Andy. Ryan, obtén los MODELOS justo antes de que comiences a preocuparte por los controladores y las vistas. Usando este enfoque, puede descubrir que el lugar correcto para todos los cálculos es el modelo de la Casa. –

Respuesta

0

Todo esto depende del tipo de datos que está creando. ¿Cómo se ve el controlador de la calculadora?

Puede crear sus propias clases en/lib y usarlas en sus modelos, lo que puede ser una buena manera de separar la lógica del controlador/ayudantes. ¿Hay alguna razón por la cual no puedas poner algo de lógica en los modelos?

+0

calculator_controller guarda datos y mueve al usuario a la siguiente página que le permite ingresar más información. Los modelos están haciendo la validación, pero eso es todo. Los cálculos que se están realizando son principalmente cálculos numéricos basados ​​en los parámetros de la casa y la sala. Intenté hacer un modelo para la calculadora, pero luego no puedo acceder a las variables desde la vista. ¿Tendría que hacer todas las variables globales entonces? – Ryan

1

Crearía una clase en RAILS_ROOT/lib/called, por ejemplo, Calculator y pondré el código allí.

Las clases en/lib/deben cargarse y estar disponibles en cualquier lugar de su aplicación.

También puede crear un objeto de rubí simple en/app/models /. No hay ninguna razón por la que todos tengan que heredar de ActiveRecord :: Base

+0

He creado un archivo calculator.rb en una aplicación/modelos que no hereda de ActiveRecord. Sin embargo, cuando muevo mi código a ese archivo, ya no puedo acceder a él desde la vista. Supongo que es porque lo hice todo con variables locales. ¿Cuál es la mejor manera de arreglar esto? Traté de cambiarlos a variables globales, pero no parece ayudar. – Ryan

+0

Al poner los métodos en los modelos, en lugar de una clase en lib /, se relaciona mejor la lógica con los datos subyacentes. Además, tiene la clara ventaja de no sufrir este problema relacionado con las variables de instancia, ya que puede llamar a los métodos en las instancias de los modelos que ya está manejando en el controlador y las vistas. La agricultura codifica en lib/tiene más sentido si es utilizada por múltiples clases en su base de código, como un Módulo Mixin, o es algo que está refactorizando en un proyecto/complemento de sidecar reutilizable. Si la lógica es parte de la base de código, guárdela con su código principal. –

5

Hay algunas maneras de abordarlo, pero la lógica ciertamente no pertenece a la vista. Tiene los diversos modelos asociados entre sí en una jerarquía clara con la parte superior de la jerarquía como modelo de la Casa, si estoy leyendo su descripción correctamente. Siendo ese el caso, agregaría un método apropiado de conjunto de métodos al modelo de la Casa que puede estar compuesto de llamadas a métodos de cálculo en los modelos de Habitación asociados con una instancia de Casa dada y en la línea de asociación. De esta forma, el cálculo relevante se puede realizar en cada nivel y mediante la composición de uno o más métodos en el nivel de modelo de la Casa, se puede tener una forma limpia, expresiva y sostenible de lidiar con los cálculos.

Una cosa que hacer, también, sería asegurarse de que cualquier cálculo que pueda realizar la base de datos sea. Por ejemplo, si hay un cálculo que un modelo de Sala puede hacer simplemente consultando sus propios datos, entonces, por supuesto, envíe esa carga computacional al DB utilizando la capacidad de ActiveRecord para invocar dicha lógica de cálculo de nivel inferior. Consulte el API docs para más detalles.

Miraría con mucho cuidado la lógica que desee y veré cómo se puede insertar en el modelo ya que es probablemente donde pertenece, cerca de los datos reales de los cálculos y dentro de las estructuras de clase que representan esos datos específicamente; No crearía un modelo solo para manejar la lógica de cálculo a menos que realmente necesite almacenar los cálculos persistentemente por alguna razón.

1

Ok, ahora puedo ver el código publicado. Puedo ver que calculator_controller en realidad no tiene cálculos, ¿están en las vistas ?. Pruebe este enfoque:

  1. Escriba una prueba que establezca un objeto que devolverá los resultados que necesita devolver al usuario de la página web, dada una casa, habitaciones o cualquier otra cosa que necesite.
  2. Crea un modelo (en modelos) para hacer que pase la prueba.
  3. Modifique el código de su controlador anterior para usar su nueva calculadora modelo
  4. Modifique las pruebas de su controlador para que también pasen. Estas pruebas, por supuesto, no necesitan probar ninguna lógica comercial.

Mi respose antes:

Si la lógica de negocio es bastante sencillo y sólo se utiliza detrás de esta aplicación web, entonces usted puede ponerlo en la carpeta app/models.

class MyCoolClass 
    def initialize(clues) 
    @other_things = OtherThing.all 
    end 
    def do_cool_thing; end 
    def calculate_coolness 
    @other_things.length 
    end 
end 

Luego, en su controlador, cree una instancia de su modelo

def index 
    @mcc = MyCoolClass "A clue as to what I want" 
    render 
end 

Luego, en sus plantillas se puede acceder a él

<%=h @mcc.calculate_coolness %> 

Tenga en cuenta que es un @other_things instance__variable de MyCoolClass y generalmente no accesible para las plantillas sin métodos de acceso definidos

+0

Me gusta construir modelos como este cuando la lógica comienza a saturar el modelo AR. –

Cuestiones relacionadas