3 votes

Comment utiliser la valeur d'un enregistrement parent dans la validation des rails ?

J'ai une application rails 3.2 dans laquelle j'ai une relation simple parent/enfant dans laquelle je dois utiliser les valeurs du parent pour valider les attributs de l'enfant. Les modèles ressemblent à ceci :

class RubricItem < ActiveRecord::Base
  attr_accessible :max_score, :min_score, :name, :order
  has_many :rubric_ranges
end

y

class RubricRange < ActiveRecord::Base
  attr_accessible :helper, :range_max, :range_min, :rubric_item_id
  validates_presence_of :helper, :range_max, :range_min
  validates :range_max, :range_min, :numericality => {:only_integer => true}
  validates :range_max, :numericality => { :greater_than => :range_min }
  belongs_to :rubric_item
end

Je veux pouvoir valider deux choses différentes. Premièrement, pour une rubric_range, je veux valider que sa valeur range_min est >= à son parent rubic.min_score et que range_max <= à son parent rubric.max_score.

Deuxièmement, je veux valider que les autres rubric_ranges ont des valeurs min/max uniques. En d'autres termes, il ne peut pas y avoir deux plages de rubriques définies pour la même valeur, donc si l'une couvre 0-2, une autre ne doit pas inclure 0, 1 ou 2 dans sa plage. Exemple : la première plage est de 0 à 2, si l'une d'entre elles définit une plage de 2 à 4, je veux qu'une erreur de validation soit générée dans la portée du parent.

Merci pour toute aide.

2voto

BroiSatse Points 18691

Vous pouvez utiliser parent presque de la même manière que vous utilisez parent :

class RubricRange < ActiveRecord::Base
  ...
  validate :has_proper_range
  ...
  def has_proper_range
    error.add(:range_min, ' cannot be smaller than RubricItem minimum score') if range_min < rubric_item.min_score
    error.add(:range_max, ' cannot be greater than RubricItem maximum score') if range_max > rubric_item.max_score
  end

Le seul problème est que si vous voulez créer un élément RubricRange avec un RubricItem en utilisant nested_attributes, la méthode build sur l'association ne définit pas la relation inverse pour les nouveaux enregistrements.

La deuxième validation peut être faite en remarquant simplement qu'il faut échouer s'il y a une autre plage avec min ou max dans la plage donnée. Donc :

validate :do_not_overlap_with_other_ranges
...
def do_not_overlap_with_other_ranges
  overlapping_ranges = self.class.where('(range_min >= :min AND range_min <= :max) OR (range_max >= :min AND range_max <= :max)', {:min => range_min, :max => range_max})
  overlapping_ranges = overlapping_ranges.where.not(:id => id) unless new_record?
  errors.add(:base, 'Range overlapping with another range') if overlapping_ranges.exists?
end

(N'hésitez pas à commenter la requête ci-dessus car je pense qu'il devrait y avoir une façon plus agréable d'écrire cela).

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