2010-12-07 49 views
7

在我的导轨应用程序中,我有一个带有start_date和end_date的模型。如果用户选择2010年1月1日作为start_date,并选择2010年1月5日作为end_date,则需要创建5个创建模型的实例(每个选定一个日期)。所以它看起来像如何覆盖导轨模型的“新”方法

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

我知道处理这个问题的一种方法是在控制器中做一个循环。像...

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

但是,我想保持我的控制器瘦,再加上我想保持它的模型逻辑。我猜我需要重写模型中的“新”方法。什么是最好的方法来做到这一点?

+0

你为什么想要? – Chowlett 2010-12-07 13:48:39

+0

我有一个用户填写的表单来创建模型。但是这种形式只是一个框架来填补我的模型的细节。该表格具有“开始”和“结束”点等详细信息。要创建一个完整的模型,需要填入开始点和结束点。我可以在控制器中执行此操作,但我认为这种类型的逻辑应该放在模型中。 – Lan 2010-12-07 13:54:43

回答

16

由于@brad说,你绝对不想重写初始化。虽然你可以覆盖after_initialize,但这看起来并不像你想要的。相反,你可能想要像@Pasta所建议的那样向类中添加工厂方法。因此,添加到您的模型:

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

然后添加到您的控制器:

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

你为什么不只是创建一个方法到你的模型像这样

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

含有这种逻辑(基本上是你的循环?)

+0

我想在模型中使用它,因为这就是创建自身的逻辑应该是的地方,不是吗?我的模型只需要一个开始和结束日期,然后就可以创建自己的“实例”。 (实例恰好是数据库表中的多行) – Lan 2010-12-07 13:30:38

+0

所以我会尽我所说在我的答案。一个create_dates类方法,你的循环调用新的内部。 – Pasta 2010-12-07 13:37:05

+0

对不起,我需要更好地说出我的问题。但基本上,我只是想知道如何覆盖MyModel.new(属性) – Lan 2010-12-07 13:42:06

2

我猜你想为你的模型属性设置默认值?

还有另一种解决方案,而不是重写;您可以设置回调:

class Model 

before_create :default_values 
def default_values 
    ... 
end 
2

您可以使用:

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

虽然地方我读它是不建议...

10

不要覆盖initialize它可能打破了很多的东西在你的模型中。如果我们知道为什么你需要我们可以更好地帮助(不完全理解你的表单是一个框架的解释,你需要表单属性来创建其他属性,见下文)。 Marcel建议我经常使用钩子。但是,如果您希望它始终发生,不仅在创建或保存对象之前,请使用挂钩。

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

此外,如果你只是寻找一些默认值就可以提供默认的访问器,是这样的:(其中some_attribute相当于你的模型属性的列名)

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

或作家

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

如果我正确理解您的评论,它看起来像你公开的形式,将使您的模型不完整的,与基于其他属性在这种形式的部分?在这种情况下,您可以使用上述方法after_initializesome_attribute=中的任何一种在您的模型上创建其他属性。

2

这种工厂方法patttern的怪胎......找到它。

如果由于某种原因不愿意使用每个@Pasta的create_date,那么可能创建一个简单的ruby对象(不支持ActiveRecord),名为YourModelFactory/Template/Whatever with two instance vars - 您可以使用标准params [:foo]来分配这些参数 - 然后在该类上定义并调用返回实际对象的方法。

你的控制器逻辑现在看起来是这样的:

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

好运。

0

严格,虽然晚了,正确的方式在一个模型覆盖

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