Rails accepts_nested_attributes_for callbacks
-
26-09-2019 - |
Question
J'ai deux modèles Ticket et TicketComment , le TicketComment est un enfant de billets.
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
Ce que je veux faire est d'imiter la fonctionnalité dans Trac, où si un utilisateur effectue une modification du billet, et / ou ajoute un commentaire, un email est envoyé aux personnes affectées au ticket.
Je veux utiliser un after_update ou after_save rappel, de sorte que je connais les informations ont été tous sauvés avant d'envoyer des e-mails.
Comment puis-je détecter des modifications au modèle (ticket.changes), ainsi que si un nouveau commentaire a été créé ou non (ticket.comments) et envoyer cette mise à jour (x modifications à y, l'utilisateur a ajouté un commentaire « texte ») dans uN email dans une méthode de rappel?
La solution
vous pouvez utiliser le ActiveRecord :: Module Sale , qui vous permet pour suivre les modifications non enregistrées.
par exemple.
t1 = Ticket.first
t1.some_attribute = some_new_value
t1.changed? => true
t1.some_attribute_changed? => true
t1.some_attribute_was => old_value
Alors dans un before_update de before_create vous devriez ceux (vous ne pouvez vérifier avant que l'enregistrement!).
Un endroit très agréable de rassembler toutes ces méthodes se trouve dans une Observer classe TicketObserver, de sorte que vous pouvez séparer votre -code « observateur » de votre modèle actuel.
par exemple.
class TicketObserver < ActiveRecord::Observer
def before_update
.. do some checking here ..
end
end
pour permettre à la classe d'observateur, vous devez ajouter dans votre environment.rb
:
config.active_record.observers = :ticket_observer
Cela devrait vous aider à démarrer:)
Ce qui concerne les commentaires liés. Si vous faites ceci:
new_comment = ticket.ticket_comments.build
new_comment.new_record? => true
ticket.comments.changed => true
Alors, ce serait exactement ce que vous avez besoin. Est-ce que fonctionne pas pour vous? Notez à nouveau: vous devez vérifier avant d'enregistrer, bien sûr:)
Je suppose que vous devez recueillir les données qui ont changé dans un before_create ou before_update, et dans un after_update / créer réellement envoyer le courrier (parce que vous êtes sûr qu'il a réussi).
Apparemment, il est toujours pas clair. Je vais faire un peu plus explicite. Je recommande d'utiliser la classe TicketObserver. Mais si vous voulez utiliser la fonction de rappel, ce serait comme ceci:
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