Rails accepts_nested_attributes_for 回调函数

5

我有两个模型TicketTicketComment,其中TicketComment是Ticket的子级。

ticket.rb

class Ticket < ActiveRecord::Base
  has_many :ticket_comments, :dependent => :destroy, :order => 'created_at DESC'

  # allow the ticket comments to be created from within a ticket form
  accepts_nested_attributes_for :ticket_comments, :reject_if => proc { |attributes| attributes['comment'].blank? }
end

ticket_comment.rb

class TicketComment < ActiveRecord::Base
  belongs_to :ticket

  validates_presence_of :comment
end

我想要做的是模仿Trac中的功能,当用户更改票务或添加评论时,会向分配给该票务的人发送电子邮件。
我想使用after_update或after_save回调,以便在发送电子邮件之前知道所有信息都已保存。
如何检测模型的更改(ticket.changes)以及是否创建了新评论(ticket.comments),并在回调方法中将此更新(x个更改到y,用户添加了评论“text”)发送到一个电子邮件中?

啊哈,我猜我误解了你的问题。抱歉。我会尝试提出一个实际的解决方案。 - Jakub Hampl
1个回答

4
你可以使用ActiveRecord::Dirty模块,它允许你跟踪未保存的更改。
例如:
t1 = Ticket.first
t1.some_attribute = some_new_value
t1.changed? => true
t1.some_attribute_changed? => true
t1.some_attribute_was => old_value 

因此,在 before_update 或 before_create 中,你应该执行这些操作(你只能在保存之前进行检查!)。

一个非常好的收集所有这些方法的地方是在 Observer-class TicketObserver 中,这样你可以将你的“观察者”代码与你的实际模型分开。

例如:

class TicketObserver < ActiveRecord::Observer
  def before_update
    .. do some checking here ..
  end
end

为了启用观察者类,您需要在environment.rb中添加以下内容:
config.active_record.observers = :ticket_observer

这应该可以帮助你入门 :)
至于链接评论方面。如果您这样做:
new_comment = ticket.ticket_comments.build
new_comment.new_record? => true
ticket.comments.changed => true

那将会是你所需要的。这对你不起作用吗? 再次注意:在保存之前你需要检查一下,当然 :)

我想你必须在 before_create 或 before_update 中收集已更改的数据,并在 after_update/create 中发送邮件(因为这样你可以确保它已成功)。

显然仍然不清楚。我会让它更加明确一些。我建议使用 TicketObserver 类。但如果你想使用回调函数,它应该像这样:

class Ticked

  before_save :check_state
  after_save :send_mail_if_needed

  def check_state
    @logmsg=""
    if ticket_comments.changed
      # find the comment
      ticket_comments.each do |c| 
        @logmsg << "comment changed" if c.changed?
        @logmsg << "comment added" if c.new_record? 
      end
    end
  end

end
def send_mail_if_needed
  if @logmsg.size > 0
    ..send mail..
  end
end

我已经有了能够运行的代码,我理解那部分。这里困难的部分是确定是否创建了TicketComment,它是一个子对象。如果包含其中一个,我需要添加其内容。不幸的是,像那样的子对象不会出现在“changes”数组中,因为它不是更改(不是脏数据)。 - Rabbott
你好,我已经相应地扩展了我的回答。现在更有意义了吗? - nathanvda
是的,我理解所有这些。我了解Dirty。但Dirty对我没有帮助。当一个表单被提交时,在控制器中我有一个哈希(params[:ticket]),创建了一个新的ticket_comment,并在该哈希中提供。ticket对象已保存。ticket_comment已保存。现在,在回调函数中,我有SELF,我如何知道是否添加了评论,以及如何访问该评论? - Rabbott
你有SELF。如果集合内部发生了变化,self.ticket_comments.changed将为true;如果在保存之前检查,那么在成功更新后,你就可以发送电子邮件了。我更新了答案以展示这一点。 - nathanvda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接