0

J'essaie d'implémenter une piste d'audit dans mon application, mais en raison de certaines exigences, je suis incapable d'utiliser des gemmes ou des plugins existants.Mise à jour d'enregistrement actif de surcharge et de contournement

Je souhaite rediriger toute tentative normale de mise à jour d'un modèle vers une méthode personnalisée qui enregistre toutes les mises à jour dans une autre table distincte (appelée Mises à jour).

L'application utilise ensuite la table de mise à jour pour réellement effectuer la mise à jour.

create_or_update En ce moment je suis surchargé pour obtenir la première partie de la fonctionnalité

def create_or_update 
    raise ReadOnlyRecord if readonly? 
    result = new_record? ? create : create_updates 
    result != false 
end 


class Update < ActiveRecord::Base 
    belongs_to :updatable, :polymorphic => true 

    after_create :update_model 

    private 

    def update_model 
    self.updatable.update_attribute self.attribute, self.new_value #infinite loop 
    end 
end 

La question est maintenant que cela provoque une boucle infinie lorsque le modèle de mise à jour tente d'effectuer réellement la mise à jour.

J'ai regardé à travers la source principale de rails pour trouver le meilleur endroit pour contourner la fonctionnalité de la première caractéristique. Je voudrais que ces mises à jour soient effectuées à l'intérieur de la transaction, mais je ne sais pas exactement où cela commence ou finit dans la pile d'enregistrements active. Je ne veux pas non plus commencer à pirater des ressources actives.

Toutes les suggestions seraient grandement appréciées.

Répondre

1

Avez-vous réellement besoin d'enregistrer les attributs dans une table distincte, puis effectuez la mise à jour après qu'un administrateur les affiche et les approuve? Si tel est le cas, vous pouvez simplement vouloir écraser la méthode de mise à jour de faire quelque chose comme ceci:

def update(perform_updates = false) 
    if perform_updates 
    latest_approved_update = UpdateAuditor.first(:conditions => { :updatable_id => self.id, :updatable_type => self.class.name, :approved => true }) 
    self.attributes = latest_approved_update.attributes 
    self.save 
    else 
    UpdateAuditor.create(:updatable_id => self.id, :updatable_type => self.class.name, :attributes => self.attributes) 
    end 
end 

MISE À JOUR: L'auteur a commenté qu'ils veulent être en mesure d'appliquer ce modèle à tous mises à jour. Pour ce faire, vous pouvez ajouter un attribut attr_accessor au modèle, disons quelque chose comme "perform_updates", qui sera bien sûr nul par défaut. Lorsque vous souhaitez effectuer la mise à jour de la base de données, vous devez d'abord définir l'attribut sur true, puis exécuter la mise à jour. Sinon, la mise à jour créera simplement un nouvel enregistrement UpdateAuditor qui devra être approuvé par un administrateur.

class Person < ActiveRecord::Base 
    has_many :audits, :class_name => "UpdateAudit", :as => :auditable 

    attr_accessor :perform_updates 

    private 

    def create_or_update 
    raise ReadOnlyRecord if readonly? 

    if new_record? 
     result = create 
     result != false 
    else 
     if perform_updates 
     latest_approved_update = audits.approved.last 

     if latest_approved_update 
      self.attributes = latest_approved_update.attributes 
      update 
     else 
      return false 
     end 
     else 
     audits.create(:updated_attributes => self.attributes) 
     end 
    end 
    end 
end 

Pour mémoire, je pense que les méthodes de l'écrasement mise à jour par défaut est un jeu dangereux, et une telle programmation est mieux dans un rappel before_update où il appartient. Une fois qu'une mise à jour est approuvée dans une interface, un observateur peut alors effectuer la mise à jour, en écrasant ce qui est actuellement là, jusqu'à ce qu'une autre modification qui a été faite puisse être approuvée. Si des mises à jour d'un objet dans la file d'attente sont actuellement approuvées, les utilisateurs peuvent être avertis que les modifications sont en attente d'approbation, etc.

+0

Ceci est proche de la fonctionnalité sauf que les mises à jour sont pré-approuvées. J'ai considéré quelque chose comme ceci mais je ne pense pas que cette solution attrapera toutes les mises à jour. Par exemple, update_attributes contournerait également UpdateAuditor. – stellard

+0

J'ai fait le changement que vous avez demandé, cependant, s'il vous plaît lire mon commentaire près du fond. –

+0

Merci beaucoup pour votre réponse. Je suis d'accord que l'écrasement de la méthode de mise à jour par défaut peut être dangereux mais je ne sais pas comment je peux accomplir exactement ce que je veux faire en utilisant un callback before_update. Comment puis-je arrêter la mise à jour après avoir créé un UpdateAudit sans me comporter de la même manière qu'une mise à jour échouée? – stellard