2010-12-07 11 views
7

En mi aplicación de rieles tengo un modelo con fecha_inicial y fecha_final. Si el usuario selecciona el 1 de enero de 2010 como start_date y 5 de enero de 2010 como end_date, quiero que haya 5 instancias de mi modelo creadas (una para cada día seleccionado). Así que se verá algo así comoCómo anular el "nuevo" método para un modelo de rieles

Jan 1, 2010 
Jan 2, 2010 
Jan 3, 2010 
Jan 4, 2010 
Jan 5, 2010 

Sé que una forma de manejar esto es hacer un ciclo en el controlador. Algo así como ...

# ...inside controller 
start_date.upto(end_date) { my_model.new(params[:my_model]) } 

Sin embargo, quiero mantener mi controlador flaco, además de que quieren mantener la lógica del modelo fuera de ella. Supongo que necesito anular el "nuevo" método en el modelo. ¿Cuál es la mejor manera de hacer esto?

+0

¿Por qué quieres? – Chowlett

+0

Tengo un formulario que rellena el usuario para crear un modelo. Pero esa forma es solo un esqueleto para completar los detalles de mi modelo. El formulario tiene detalles como puntos de "inicio" y "final". Para crear un modelo completo, se deben completar los puntos de inicio y fin. Puedo hacer esto en el controlador, pero creo que este tipo de lógica debería ir en el modelo. – Lan

Respuesta

16

Como dice @brad, definitivamente no desea anular la inicialización. Aunque podría anular after_initialize, eso realmente no se parece a lo que quiere aquí. En cambio, es probable que desee agregar un método de fábrica a la clase como sugiere @Pasta. Así que añadir esto a su modelo:

def self.build_for_range(start_date, end_date, attributes={}) 
    start_date.upto(end_date).map { new(attributes) } 
end 

Y a continuación, añadir esto a su controlador:

models = MyModel.build_for_range(start_date, end_date, params[:my_model]) 
if models.all?(:valid?) 
    models.each(&:save) 
    # redirect the user somewhere ... 
end 
2

¿por qué no acaba de crear un método en su modelo como este

def self.create_dates(params) 
    [...] 
    end 

que contiene esta lógica (básicamente su bucle?)

+0

Lo quiero en el modelo porque ahí es donde debería estar la lógica para crearse, ¿no? Mi modelo solo necesita una fecha de inicio y finalización y luego podrá crear "una instancia" de sí mismo. (la instancia simplemente resulta ser varias filas en la tabla de la base de datos) – Lan

+0

así que haría lo que dije en mi respuesta. un método de clase create_dates con su bucle invocando nuevo dentro. – Pasta

+0

Lo siento, necesito responder mi pregunta mejor. Pero básicamente, solo quiero saber cómo anular MyModel.new (atributos) – Lan

2

supongo que desea establecer los valores por omisión para el atributo model ?

Hay otra solución que reemplaza; puede establecer las devoluciones de llamada:

class Model 

before_create :default_values 
def default_values 
    ... 
end 
2

Se puede utilizar:

def initialize(attributes = nil) 
    # do your stuff... 
end 

Aunque alguna parte leí que no era recomendable ...

+3

ActiveRecord hace un montón de cosas locas y no se garantiza que este método se ejecute como era de esperar. – tadman

10

No invalide initialize Se podría romper un montón de cosas en tus modelos. SI supiéramos por qué lo necesitábamos, podríamos ayudarlo mejor (no entiendo completamente su explicación de que la forma es un esqueleto, quiere que los atributos de la forma creen otros atributos, ver más abajo). A menudo uso un gancho como Marcel sugirió. Pero si quiere que suceda todo el tiempo, no solo antes de crear o guardar un objeto, use el gancho after_initialize.

def after_initialize 
    # Gets called right after Model.new 
    # Do some stuff here 
end 

Además, si usted está buscando para algunos valores por defecto que puede proporcionar métodos de acceso por defecto, algo así como: (donde some_attribute se corresponde con el nombre de la columna de su atributo model)

def some_attribute 
    attributes[:some_attribute] || "Some Default Value" 
end 

o un escritor

def some_attribute=(something) 
    attributes[:some_attribute] = something.with_some_changes 
end 

Si entiendo tu comentario correctamente, parece que se expone una forma que haría que su modelo incompleto, con los otros atributos basados en partes de esta forma? En este caso, puede usar cualquiera de los métodos anteriores after_initialize o some_attribute= para crear otros atributos en su modelo.

+1

Eche un vistazo al ActiveRecord :: Base source (https://github.com/rails/rails/blob/v3.0.3/activerecord/lib/active_record/base.rb) Mire el método de inicialización y vea qué está pasando, es buscando columnas desde el archivo db, asignando variables de instancia, etc., si anulas esto pero no configuras estos atributos, no hay garantía de que active_record se comporte correctamente. – brad

+0

Tenga en cuenta que en Rails 3.2.x, las claves en 'attributes' son cadenas en oposición a los símbolos. Entonces necesitarías 'attributes [" some_attribute "]' en el párrafo anterior. – steakchaser

+2

No hay razón para no anular la inicialización. Contrariamente, si nos fijamos en el código fuente de los raíles, comprenderá que la inicialización estaba destinada a ser anulada. Todo lo que necesita hacer es llamar a super en su inicialización anulada, pero es una regla que se espera que todos los desarrolladores de ruby ​​y desarrolladores de rails esperen silenciosamente que lo haga. –

2

Esto apesta al método de fábrica patttern ... búscalo.

Si por alguna razón es reacio ir a create_date por @Pasta, entonces posiblemente solo cree un objeto ruby ​​simple (no respaldado por ActiveRecord), llamado YourModelFactory/Template/Whatever con dos instancias vars: puede usar su estándar params [: foo] para asignar estos - luego define y llama un método en esa clase que devuelve tus objetos reales.

Su lógica del controlador ahora se ve algo como esto:

mmf = MyModelFactory.new(params[:foo]) 
objs = mmf.create_real_deal_models 

Buena suerte.

+0

Estoy de acuerdo con esto, ahora que se ha explicado que realmente quiere crear varios modelos, creo que una fábrica está en orden. – brad

+2

Encuentro que las fábricas en los modelos se hacen mejor como métodos de clase que las clases separadas. Así que def.make_me_things en MakeMeThings.new. – Trotter

+2

Estoy totalmente +1 en def.make_me_things, solo intento hacer que parezca más elegante para el póster original. – Cory

0

En sentido estricto, aunque tarde, de la manera adecuada para anular nueva en un modelo es

def initialize(args) 
    # 
    # do whatever, args are passed to super 
    # 
    super 
end 
Cuestiones relacionadas