假设在Ruby中进行以下数据库迁移:
create_table :question_votes do |t| t.integer :user_id t.integer :question_id t.integer :vote t.timestamps end
进一步假设我希望DB中的行包含唯一(user_id,question_id)对。为了实现这一目标,在模型中投入的粉尘是什么?
validates_uniqueness_of :user_id, :question_id似乎只是根据用户ID使行唯一,并且按问题ID唯一,而不是该对唯一。
答案 0 :(得分:89)
validates_uniqueness_of :user_id, :scope => [:question_id]
如果您需要包含其他列(或更多列),也可以将其添加到范围中。例如:
validates_uniqueness_of :user_id, :scope => [:question_id, :some_third_column]
答案 1 :(得分:25)
如果使用mysql,您可以使用唯一索引在数据库中执行此操作。它类似于:
add_index :question_votes, [:question_id, :user_id], :unique => true
当您尝试保存question_id / user_id的双重组合时,这会引发异常,因此您必须尝试并找出要捕获和处理的异常。
答案 2 :(得分:15)
来自RailsGuides。 validates
也有效:
class QuestionVote < ActiveRecord::Base
validates :user_id, :uniqueness => { :scope => :question_id }
end
答案 3 :(得分:14)
最好的方法是使用两者,因为当唯一性验证通过时,rails不是100%可靠。
您可以使用:
validates :user_id, uniqueness: { scope: :question_id }
并且在安全方面100%,在您的db(MySQL ex)上添加此验证
add_index :question_votes, [:user_id, :question_id], unique: true
然后您可以使用以下方式处理控制器:
rescue ActiveRecord::RecordNotUnique
所以现在你100%安全,你没有重复的价值:)
答案 4 :(得分:10)
除了编写自己的验证方法之外,使用validates_uniqueness_of
可以做的最好的是:
validates_uniqueness_of :user_id, :scope => "question_id"
这将检查user_id在所有行中是否唯一,并且与您尝试插入的记录具有相同的question_id。
但那不是你想要的。
我相信您正在寻找:user_id
和:question_id
的组合在整个数据库中的独特性。
在这种情况下,你需要做两件事:
答案 5 :(得分:2)
当您创建新记录时,这不起作用,因为您的父模型的id
在验证时仍然不存在。
这应该适合你。
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
在上面的代码中,我得到所有b_id
个参数集合,然后比较唯一值和获得的b_id之间的长度是否相等。
如果等于则意味着没有重复b_id
。
注意:不要忘记在数据库的列中添加唯一。