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



我有一个名为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 

您可以将Conversation模型中的范围验证定义为

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)

来源:链接

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

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内部验证一样,由于数据库访问的竞争条件,这实际上并不能保证您永远不会进行两次对话,为此,您还需要在数据库中有一个匹配的唯一索引,该索引将依赖于这种类型的索引的数据库(如果您正在使用的数据库确实可以这样做的话)

最新更新