56 votes

Valider avant de détruire

J'ai trois classes: l'École, le Compte et le Administratorship.

L'école

has_many :administatorships

has_many :les administrateurs, :par => :administratorships

Compte

has_many :administratorships

Administratorship

belongs_to :account
belongs_to :school

before_destroy :confirm_presence_of_alternate_administratorship_in_school

protected

def confirm_presence_of_alternate_administratorship_in_school
    unless school.administrators.count(["administratorships.account_id != #{id}"]) > 0
        errors.add_to_base "The school must have at least one administrator"
    end
end

Maintenant, ce que je voudrais arriver, c'est que lorsque j'appelle destroy sur une instance de Administratorship, pour ajouter une erreur dans le modèle et d'empêcher la destruction du modèle. J'ai enlevé le moins d'instruction pour voir si c'était la prévention de l'erreur d'être ajouté, ce n'était pas le cas. Il semble que le fait d'avoir des erreurs sur le modèle n'empêche pas le détruire de se produire.

Donc ma question est, est-il possible que je peux les empêcher de le détruire de se produire à l'aide de validations? Je me rends compte que je pouvais définir une méthode qui détruit seulement si la condition ci-dessus est remplie, mais il semble qu'une approche de validation est une solution plus élégante.

15voto

Ryan Points 4221

De retour false de votre méthode de validation permettra d'éviter l'enregistrement à partir détruites.

Exemple:

def confirm_presence_of_alternate_administratorship_in_school
  unless school.administrators.count(["administratorships.account_id != #{id}"]) > 0
    # errors.add_to_base() is deprecated in Rails 3. Instead do...
    errors.add(:base, "The school must have at least one administrator")

    # this will prevent the object from getting destroyed
    return false
  end
end

Note de côté: j'ai eu du mal avec ce message d'erreur ne s'affiche pas. La validation du travail et de l'objet ne serait pas supprimé, mais il n'y aurait pas de message pour me permettre de savoir ce qui s'est passé. La raison pour cela est que le contrôleur a été redirigé vers l'index de la vue plutôt que de rendre le supprimer de la vue (si il y a une erreur lors de la création d'un nouvel utilisateur par exemple, il va rendre :action => 'nouveau'. Dans ce cas, il n'est pas de supprimer la vue). Lorsque cela s'est produit, la variable d'instance à laquelle le message d'erreur a été placé (dans les erreurs.ajouter(:base,"message")) est en cours de réinitialisation, qui détruit l'erreur dans le processus.

1voto

Hugo Forte Points 484

J'ai fini par utiliser le code d'ici pour créer une substitution can_destroy sur activerecord: https://gist.github.com/andhapp/1761098

 class ActiveRecord::Base
  def can_destroy?
    self.class.reflect_on_all_associations.all? do |assoc|
      assoc.options[:dependent] != :restrict || (assoc.macro == :has_one && self.send(assoc.name).nil?) || (assoc.macro == :has_many && self.send(assoc.name).empty?)
    end
  end
end
 

Cela a l’avantage supplémentaire de rendre trivial de masquer / afficher un bouton de suppression sur l’interface utilisateur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X