2010-05-13 2 views
24

Je sais que je peux exiger un champ en ajoutant validates_presence_of :field au modèle. Cependant, comment dois-je exiger qu'au moins un champ soit obligatoire, sans nécessiter de champ particulier?Rails: comment exiger au moins un champ pour ne pas être vide

merci à l'avance

- Deb

+1

Je crois que vous devez écrire votre propre validation –

Répondre

24

Vous pouvez utiliser:

validate :any_present? 

def any_present? 
    if %w(field1 field2 field3).all?{|attr| self[attr].blank?} 
    errors.add :base, "Error message" 
    end 
end 

EDIT: mis à jour à partir de la réponse originale pour Rails 3+ selon le commentaire.

Mais vous devez fournir des noms de champs manuellement. Vous pouvez obtenir toutes les colonnes de contenu d'un modèle avec Model.content_columns.map(&:name), mais aussi les colonnes created_at et updated_at, et ce n'est probablement pas ce que vous voulez.

+8

Pour mettre à jour cette réponse pour Rails 3, utilisez 'errors.add: base," Message d'erreur "' car add_to_base est obsolète –

7

Ajouter une méthode validate à votre modèle:

def validate 
    if field1.blank? and field2.blank? and field3.blank? # ... 
    errors.add_to_base("You must fill in at least one field") 
    end 
end 
+0

Je crois que ce n'est pas très bon s'il y a beaucoup de domaines:/ –

+0

Je ne peux pas imaginer qu'il voudrait vérifier si un champ _En toute sa model_ est présent. J'ai supposé que c'était un ensemble particulier de champs. –

+0

votre réponse est également correcte, alors j'ai voté aussi. Cependant, j'ai fini par utiliser la réponse de Voyta. Merci pour la réponse! – deb

2

Je crois que quelque chose comme ce qui suit travailler

class MyModel < ActiveRecord::Base 
    validate do |my_model| 
     my_model.my_validation 
    end 

    def my_validation  
     errors.add_to_base("Your error message") if self.blank? 
     #or self.attributes.blank? - not sure 
    end 
end 
1

Pour aller plus loin avec @ réponse de Votya, voici un moyen de récupérer toutes les colonnes en plus created_at et updated_at (et éventuellement, tous les autres que vous voulez jeter):

# Get all column names as an array and reject the ones we don't want 
Model.content_columns.map(&:name).reject {|i| i =~ /(created|updated)_at/} 

Par exemple:

1.9.3p327 :012 > Client.content_columns.map(&:name).reject {|i| i =~ /(created|updated)_at/} 
=> ["primary_email", "name"] 
7

est ici une version réutilisable:

class AnyPresenceValidator < ActiveModel::Validator 
    def validate(record) 
    unless options[:fields].any?{|attr| record[attr].present?} 
     record.errors.add(:base, :blank) 
    end 
    end 
end 

Vous pouvez l'utiliser dans votre modèle avec:

validates_with AnyPresenceValidator, fields: %w(field1 field2 field3) 
+0

Au lieu d'associer 'all?' Avec 'blank? 'Ici, vous pouvez également associer' any? 'Avec 'present?' de sorte que le code lui-même suive la sémantique du nom du validateur – user456584

+0

J'ai mis à jour la solution selon votre suggestion. –

+0

C'est clairement la meilleure réponse! – micapam

Questions connexes