当我在Rails中实例化对象时如何初始化属性?

时间:2010-06-17 04:04:14

标签: ruby-on-rails model attributes initialization dry

Clients有很多Invoices。发票具有number属性,我想通过递增客户的先前发票编号来初始化该属性。

例如:

@client = Client.find(1)
@client.last_invoice_number
> 14
@invoice = @client.invoices.build
@invoice.number
> 15

我希望将此功能添加到我的Invoice模型中,但我不确定如何操作。这就是我想象的代码:

class Invoice < ActiveRecord::Base
  ...
  def initialize(attributes = {})
    client = Client.find(attributes[:client_id])
    attributes[:number] = client.last_invoice_number + 1
    client.update_attributes(:last_invoice_number => client.last_invoice_number + 1)
  end
end

但是,当我致电attributes[:client_id]时,@client.invoices.build 未设置

如何以及何时初始化发票client_id,以及何时可以使用它来初始化发票number?我可以将这个逻辑放入模型中,还是必须将它放在控制器中?

4 个答案:

答案 0 :(得分:7)

生成向用户表添加invoices_number列的迁移。然后在Invoice模型中写下这个:

class Invoice < ActiveRecord::Base
  belongs_to :user, :counter_cache => true
  ...
end

创建发票后,这将自动为用户增加invoices_count属性。

答案 1 :(得分:5)

怎么样:

class Invoice < ActiveRecord::Base
  ...
  def initialize(attributes = {})
    super
    self.number = self.client.invoices.size + 1 unless self.client.nil?
  end
end

答案 2 :(得分:1)

首先,您不需要使用属性集合,只需执行self.client_id即可。更好的是,只要您的belongs_to :client中有Invoice,就可以self.client.last_invoice_number。最后,如果更新或创建失败,您几乎总是想要引发异常,因此习惯使用update_attributes!,这是一个更好的默认选择。 (如果您对这些要点有任何疑问,请询问,我会详细介绍)

现在已经不在了,你遇到了一些使用ActiveRecord的问题,初始化方法几乎永远不是正确的选择。 AR为您提供了一系列方法,可以连接到您需要的生命周期的任何一点。这些是

after_create
after_destroy
after_save
after_update
after_validation
after_validation_on_create
after_validation_on_update
before_create
before_destroy
before_save
before_update
before_validation
before_validation_on_create
before_validation_on_update

你可能想要的是挂钩到before_create。像这样的东西

def before_create
  self.number ||= self.client.last_invoice_number + 1 unless self.client
end

它会做什么,它将为您的客户端启动数据库,获取最后一个发票号,将其递增1,并将其设置为新号码,但前提是您尚未设置号码(| | =将分配,但仅在左侧为零的情况下,并且仅当您在保存之前设置了客户端(或client_id)时才会分配。

答案 3 :(得分:1)

根据Jonathan R. Wallace的评论,以下是关于after_initialize的一些有用的讨论: http://blog.dalethatcher.com/2008/03/rails-dont-override-initialize-on.html