Rails はコールバックに対して_nested_attributes_を受け入れます
-
26-09-2019 - |
質問
2つのモデルを持っています チケット そして チケットコメント, 、TicketComment は 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
チケットコメント.rb
class TicketComment < ActiveRecord::Base
belongs_to :ticket
validates_presence_of :comment
end
私がやりたいのは、Trac の機能を模倣することです。ユーザーがチケットに変更を加えたり、コメントを追加したりすると、チケットに割り当てられているユーザーに電子メールが送信されます。
after_update または after_save コールバックを使用して、電子メールを送信する前に情報がすべて保存されたことを確認したいと考えています。
モデルへの変更 (ticket.changes) と新しいコメントが作成されたかどうか (ticket.comments) を検出し、この更新 (x が y に変更、ユーザーがコメント「テキスト」を追加) を 1 つの電子メールで送信するにはどうすればよいですか?コールバックメソッド?
解決
あなたがすることができますのActiveRecord ::ダーティのモジュールを、使用することができます未保存の変更を追跡します。
例えばます。
t1 = Ticket.first
t1.some_attribute = some_new_value
t1.changed? => true
t1.some_attribute_changed? => true
t1.some_attribute_was => old_value
だから、before_createのbefore_update内側にあなたがそれら(あなただけ保存する前に確認することができます!)する必要があります。
は、すべてのこれらのメソッドを収集するためにA非常に素晴らしい場所は、オブザーバークラスであります> TicketObserverので、あなたの実際のモデルから、あなたの「オブザーバー」-codeを区切ることができます。
例えばます。
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に/実際に作成する(そして、あなたは必ずそれが成功しているため)メールを送信ます。
どうやらそれはまだ明らかではありません。私はそれが少しより明確になります。私は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