Rails acceptpts_nested_attributes_for для обратных вызовов - PullRequest
4 голосов
/ 12 мая 2010

У меня есть две модели Ticket и TicketComment , 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') в ОДИН электронный адрес в методе обратного вызова?

1 Ответ

4 голосов
/ 12 мая 2010

вы можете использовать модуль ActiveRecord :: Dirty , который позволяет отслеживать несохраненные изменения.

* 1005 Е.Г. *

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 вы должны это сделать (вы можете проверить только перед сохранением!).

Очень хорошее место для сбора всех этих методов - класс наблюдателя TicketObserver, так что вы можете отделить свой код "наблюдателя" от вашей реальной модели.

* 1014 Е.Г. *

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
...