验证引用相同类型实体的两列的唯一性

时间:2016-01-11 18:20:26

标签: ruby-on-rails validation ruby-on-rails-4

我有一个名为Conversation的模型,其中包含两个属性user_1 and user_2和以下验证:

class Conversation < ActiveRecord::Base
    2.times { |time| belongs_to :"user_#{time + 1}", class_name: 'User' }
    has_many :messages, dependent: :destroy

    validates :user_1, :user_2, presence: true
    validates :user_1_id, uniqueness: { scope: :user_2_id,
                                  message: 'Cannot have two conversation with the same user' }
    validates :user_2_id, uniqueness: { scope: :user_1_id,
                                  message: 'Cannot have two conversation with the same user' }
end

这些验证将避免:

user_1  |  user_2              user_1 | user_2  
  1     |    2     and  also      2   |   1
  1     |    2                    2   |   1 

是否可以添加活动记录验证以避免这些?

user_1 |  user_2
   1   |     2
   2   |     1 

2 个答案:

答案 0 :(得分:0)

没有内置验证器,但您可以使用自定义验证

def validate(conv)
  unless Conversation.where(user_1_id: conv.user_2_id, user_2_id, conv.user_1_id).empty?
    record.errors[:base] << "duplicate conversation exists"
  end
end

注意 - 就像所有rails内部验证一样,这实际上并不能保证由于数据库访问的竞争条件而永远不会得到两个对话,因为你还需要在数据库中有一个匹配的唯一索引,对于这种类型的索引,它将依赖于数据库(如果它实际上可以用于您正在使用的数据库)

答案 1 :(得分:0)

您可以在对话模型中将范围验证定义为

scope :between, -> (user_1_id,user_2_id) do
   where(“(conversations.user_1_id = ? AND conversations.user_2_id =?) OR (conversations.user_1_id = ? AND conversations.user_2_id =?)”, user_1_id,user_2_id, user_2_id, user_1_id)
end

并将其用作:

@conversation = Conversation.between(id1,id2)

来源:link