Debe rieles de modelos en cuestión con otros modelos para el bien de la flaca controladores?

StackOverflow https://stackoverflow.com/questions/64214

  •  09-06-2019
  •  | 
  •  

Pregunta

He leído en todas partes que la lógica de negocios que pertenece a los modelos y no en el controlador, pero ¿dónde está el límite?Estoy jugando con un personal de contabilidad de la aplicación.

Account
Entry
Operation

Cuando se crea una operación sólo es válida si las entradas correspondientes se crean y se vinculan a las cuentas para que la operación es equilibrada por ejemplo comprar un 6-pack :

o=Operation.new({:description=>"b33r", :user=>current_user, :date=>"2008/09/15"})
o.entries.build({:account_id=>1, :amount=>15})
o.valid? #=>false
o.entries.build({:account_id=>2, :amount=>-15})
o.valid? #=>true

Ahora el formulario que se muestra al usuario en el caso de operaciones básicas se ha simplificado para ocultar las entradas de los detalles, las cuentas son seleccionados entre 5 predeterminado por el tipo de operación solicitada por el usuario (inicializar la cuenta -> la equidad de la cuenta, pasar de activos->gastos, obtener ingresos->activos, préstamos de pasivos->activos, pagar la deuda de los activos->pasivos ...) quiero las entradas creadas a partir de los valores predeterminados.

Yo también quiero ser capaz de crear operaciones más complejas (más de 2 entradas).Para este segundo caso de uso que voy a tener una forma diferente, donde la complejidad adicional está expuesto.Este segundo caso de uso me impide incluyendo una tarjeta de débito y de crédito de campo en la Operación y deshacerse de el enlace de Inscripción.

Cuál es la mejor forma ?Utilizando el código anterior en un SimpleOperationController como yo por el momento, o la definición de un nuevo método en el Funcionamiento de la clase, así que puedo llamar a la Operación.new_simple_operation(params[:operación])

No es que se rompa la separación de preocupaciones para crear y manipular la Entrada de objetos a partir de la Operación de clase ?

No estoy buscando consejos sobre mi retorcida principios de contabilidad :)

editar -- parece Que no me expreso muy claramente.No estoy tan preocupado acerca de la validación.Estoy más preocupado por donde la lógica de creación de código debe ir :

suponiendo que la operación en el controlador se llama pasar, cuando el uso de gastar, los parámetros de hash, que contendrá :cantidad, fecha, descripción.De crédito y débito de las cuentas se derivan de la acción que se llama, pero entonces tengo que crear todos los objetos.Sería mejor tener

#error and transaction handling is left out for the sake of clarity
def spend
  amount=params[:operation].delete(:amount)#remove non existent Operation attribute
  op=Operation.new(params[:operation])
  #select accounts in some way
  ...
  #build entries
  op.entries.build(...)
  op.entries.build(...)
  op.save
end

o crear un método en la Operación que haría que el de arriba se ven como

def spend
  op=Operation.new_simple_operation(params)
  op.save
end

esto sin duda dará una mucho más delgado controlador y un gordo modelo, pero, a continuación, el modelo de crear y almacenar instancias de otros modelos, que es donde está mi problema.

¿Fue útil?

Solución

pero, a continuación, el modelo de crear y almacenar instancias de otros modelos, que es donde está mi problema.

¿Qué hay de malo con esto?

Si tu "lógica de negocio", afirma que una Operación debe tener un conjunto válido de las Entradas, entonces seguramente no hay nada de malo para el Funcionamiento de la clase para conocer, y de acuerdo con su Entrada de objetos.

Sólo te de problemas si usted toma esto demasiado lejos, y tienen sus modelos de la manipulación de las cosas que no necesita saber acerca de, como un EntryHtmlFormBuilder o lo que sea :-)

Otros consejos

Atributos virtuales (más info aquí y aquí) nos pueden ayudar en gran medida.Pasar el conjunto de parámetros de regreso a la modelo mantiene las cosas simples en el controlador.Esto le permitirá construir dinámicamente su forma y construir fácilmente las entradas de los objetos.

class Operation
  has_many :entries

  def entry_attributes=(entry_attributes)
    entry_attributes.each do |entry|
      entries.build(entry)
    end
  end

end

class OperationController < ApplicationController
  def create
    @operation = Operation.new(params[:opertaion])
    if @operation.save
      flash[:notice] = "Successfully saved operation."
      redirect_to operations_path
    else
      render :action => 'new'
    end
  end
end

El guardar fallará si no todo es válido.Lo que nos lleva a la validación.Debido a que cada Entrada está solo y usted debe revisar todas las entradas en la "creación" probablemente debería reemplazar validar en la Operación:

class Operation
  # methods from above
  protected
    def validate
      total = 0
      entries.each { |e| t += e.amount }
      errors.add("entries", "unbalanced transfers") unless total == 0
    end
end

Ahora usted recibirá un mensaje de error que indica al usuario que las cantidades que se apaga y se debería solucionar el problema.Usted puede conseguir realmente de lujo aquí y añade mucho valor por ser específicos sobre el problema, como les digo lo mucho que se fuera.

Es más fácil pensar en términos de cada entidad, la validación de sí mismo, y las entidades que dependen el uno del otro delegar su estado para que el estado de sus entradas asociadas.En tu caso, por ejemplo:

class Operation < ActiveRecord::Base
  has_many :entries
  validates_associated :entries
end

validates_associated comprobará si cada uno de los asociados de la entidad es válida (en este caso, todas las entradas, si la operación ha de ser válida).

Es muy tentador tratar de validar toda la jerarquías de los modelos como un todo, pero como usted dijo, el lugar en el que sería más fácil de hacer es el controlador, el cual debe actuar como un router de solicitudes y respuestas que en el trato con la lógica de negocio.

La manera en que yo lo veo es que el controlador debe reflejar el usuario final ver y traducir las solicitudes en el modelo de las operaciones y de las respuestas a la vez que hacía el formato.En su caso hay 2 tipos de operaciones que representan las operaciones simples con un valor predeterminado de la cuenta/de entrada, y las operaciones más complejas que se han seleccionado por el usuario de las entradas y de las cuentas.Los formularios deben reflejar la vista de usuario (2 formularios con campos diferentes), y no debe ser de 2 acciones en el controlador para que coincida.El controlador sin embargo debe tener ninguna lógica acerca de cómo los datos se manipulan sólo cómo recibir y responder.Me gustaría tener los métodos de la clase sobre el Funcionamiento de la clase que tomar en la debida datos de los formularios y crea uno o más objetos según sea necesario, o a los métodos de la clase en una clase de apoyo que no es un modelo de AR, pero tiene lógica del negocio que cruza los límites del modelo.La ventaja de la utilidad independiente de la clase es que mantiene cada modelo centrado en un solo propósito, el lado negativo es que la utilidad de las clases no tienen definido el lugar para vivir.Los pongo en lib/ pero Raíles no especificar un lugar para el modelo ayudantes como tal.

Si usted está preocupado acerca de la incrustación de esta lógica en cualquier modelo en particular, ¿por qué no ponerlas en un observador de la clase, que va a mantener la lógica de la creación de los elementos asociados independientes de las clases observadas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top