2010-05-11 2 views
4

У меня есть две модели билетов и TicketComment, то TicketComment является дочерним билете.Rails accepts_nested_attributes_for обратных вызовов

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, добавлен комментарий пользователя «текст») в ОДНОМ электронном письме в методе обратного вызова?

+0

Ага, я думаю, я неверно истолковал ваш вопрос. Извиняюсь. Я постараюсь придумать реальное решение. –

ответ

4

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

E.g.

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 Observer-class, поэтому вы можете отделить свой «наблюдательный» -код от вашей реальной модели.

E.g.

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 
+0

У меня уже есть грязный код, я понимаю эту часть. Трудная часть здесь заключается в определении того, был ли создан TicketComment, который является дочерним объектом. Если кто-то был включен, мне нужно добавить его содержимое. К сожалению, такие дети не отображаются в массиве «changes», поскольку это не изменение (не грязное). – Rabbott

+0

Привет, я расширил свой ответ соответственно. Теперь это имеет смысл? – nathanvda

+0

Да, я понимаю все это. Я понимаю Грязный. Грязный не помогает мне. Когда форма отправляется, в контроллере у меня есть хэш (params [: ticket]), создается новый ticket_comment и предоставляется в пределах этого хеша. Объект билета сохраняется. файл ticket_comment сохраняется. Теперь, в обратном вызове, у меня есть SELF, откуда я знаю, что добавлен комментарий, и как мне добраться до этого комментария? – Rabbott