如何覆盖rails模型的“new”方法

在我的rails应用程序中,我有一个带有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]) } 

但是,我想保持我的控制器瘦,加上我想保持模型逻辑不在其中。 我猜我需要覆盖模型中的“新”方法。 最好的方法是什么?

正如@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 

不要覆盖initialize它可能会破坏模型中的很多东西。 如果我们知道为什么你需要我们可以帮助更好(不完全理解你对forms的解释是骨架,你想要表单属性来创建其他属性??见下文)。 正如马塞尔建议的那样,我经常使用钩子。 但是,如果您希望它始终发生,而不是在创建或保存对象之前,请使用after_initialize挂钩。

 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=然后在模型上创建其他属性。

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

除了重写之外,还有另一种解决方案; 你可以设置回调:

 class Model before_create :default_values def default_values ... end 

为什么不像这样在模型中创建一个方法呢?

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

包含这个逻辑(基本上是你的循环?)

您可以使用:

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

虽然在某处我读到它并不值得推荐……

这种工厂方法模式的臭气……寻找它。

如果你因某些原因不愿意为@Pasta使用create_date,那么可能只创建一个简单的ruby对象(不支持ActiveRecord),名为YourModelFactory / Template /无论有两个实例变量 – 你可以使用你的标准参数[:foo] ]分配这些 – 然后在该类上定义并调用一个返回真实对象的方法。

您的控制器逻辑现在看起来像这样:

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

祝好运。

严格来说,尽管很晚,在模型中覆盖的正确方法是

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