Supposons la migration de base de données suivante dans Ruby:
create_table: question_votes do | t | t.integer: user_id t.integer: question_id t.integer: vote t. horodatages fin
Supposons en outre que je souhaite que les lignes de la base de données contiennent des paires uniques (user_id, question_id). Quelle est la bonne poussière à mettre dans le modèle pour y parvenir?
validates_uniqueness_of: user_id,: question_id
validates_uniqueness_of :user_id, :scope => [:question_id]
si vous devez inclure une autre colonne (ou plus), vous pouvez également l'ajouter à la portée. Exemple:
validates_uniqueness_of :user_id, :scope => [:question_id, :some_third_column]
Si vous utilisez mysql, vous pouvez le faire dans la base de données en utilisant un index unique. C'est quelque chose comme:
add_index :question_votes, [:question_id, :user_id], :unique => true
Cela va déclencher une exception lorsque vous essayez d'enregistrer une combinaison doublée de question_id/user_id, vous devrez donc expérimenter et déterminer quelle exception intercepter et gérer.
De RailsGuides . validates
fonctionne aussi:
class QuestionVote < ActiveRecord::Base
validates :user_id, :uniqueness => { :scope => :question_id }
end
La meilleure façon est d'utiliser les deux, car Rails n'est pas fiable à 100% lorsque la validation de l'unicité passe par.
Vous pouvez utiliser:
validates :user_id, uniqueness: { scope: :question_id }
et pour être sûr à 100%, ajoutez cette validation sur votre db (ex MySQL)
add_index :question_votes, [:user_id, :question_id], unique: true
puis vous pouvez gérer votre contrôleur en utilisant:
rescue ActiveRecord::RecordNotUnique
Alors maintenant, vous êtes sûr à 100% que vous n'aurez pas de valeur en double :)
Sauf pour écrire votre propre méthode de validation, le mieux que vous puissiez faire avec validates_uniqueness_of
est-ce:
validates_uniqueness_of :user_id, :scope => "question_id"
Cela vérifiera que le user_id est unique dans toutes les lignes avec le même question_id que l'enregistrement que vous essayez d'insérer.
Mais ce n'est pas ce que vous voulez.
Je pense que vous recherchez la combinaison de :user_id
et :question_id
pour être unique dans la base de données.
Dans ce cas, vous devez faire deux choses:
Lorsque vous créez un nouvel enregistrement, cela ne fonctionne pas car le id
de votre modèle parent n'existe pas encore au moment des validations.
Cela devrait fonctionner pour vous.
class B < ActiveRecord::Base
has_many :ab
has_many :a, :through => :ab
end
class AB < ActiveRecord::Base
belongs_to :b
belongs_to :a
end
class A < ActiveRecord::Base
has_many :ab
has_many :b, :through => :ab
after_validation :validate_uniqueness_b
private
def validate_uniqueness_b
b_ids = ab.map(&:b_id)
unless b_ids.uniq.length.eql? b_ids.length
errors.add(:db, message: "no repeat b's")
end
end
end
Dans le code ci-dessus, je reçois tous les b_id
de la collection de paramètres, puis comparer si la longueur entre les valeurs uniques et b_id obtenues sont égales.
Si sont égaux signifie qu'il n'y a pas de répétition b_id
.
Remarque: n'oubliez pas d'ajouter unique dans les colonnes de votre base de données.