【问题标题】:Rails Uniqueness Between 3 Columns When 2 Columns are Foreign Keys to the Same Table当 2 列是同一个表的外键时,Rails 3 列之间的唯一性
【发布时间】:2020-02-24 15:21:10
【问题描述】:

我有两个表,资产和关系。它们看起来像这样(加上我为简洁起见省略的其他列):

# Table name: relationships
#
#  id             :uuid             not null, primary key
#  asset1_id      :uuid             not null
#  asset2_id      :uuid             not null
#  type           :string           not null
# Table name: assets
#
#  id             :uuid             not null, primary key
#  type           :string           not null
#  name           :string           not null

我希望两个资产之间的某种类型的关系是唯一的。例如,假设我有一个membership 类型的关系。

Relationship.create!(type: 'membership', asset1_id: '61d58a49-86a9-4d7f-b069-2ed1fa27b387', asset2_id: '1856df48-3193-45de-bef0-122cd9f58d7b')

如果我尝试再次创建该记录,我可以使用validates :type, uniqueness: { scope: [:asset1_id, :asset2_id] }add_index :relationships, [:type, :asset1_id, :asset2_id], unique: true 轻松阻止它,但是当我使用这些时,以下情况不会阻止:

Relationship.create!(type: 'membership', asset1_id: '1856df48-3193-45de-bef0-122cd9f58d7b', asset2_id: '61d58a49-86a9-4d7f-b069-2ed1fa27b387')

注意这里和之前的记录是一样的,只是资产id的顺序颠倒了。

如何防止这种情况(最好在数据库级别)?

【问题讨论】:

    标签: ruby-on-rails ruby postgresql unique-constraint


    【解决方案1】:

    您可以通过添加自定义验证在应用程序级别执行此操作

    validates :type, uniqueness: { scope: [:asset1_id, :asset2_id] }
    validate :reverse_type_uniqueness
    
    def reverse_type_uniqueness
      duplicate_present = self.class.where(type: type, asset1_id: asset2_id, asset2_id: asset1_id).exists?
      errors.add(:base, "Duplicate present") if duplicate_present?
    end
    

    要在 DB 级别实现 2 面唯一索引,这是一个示例,虽然不是很直接

    https://dba.stackexchange.com/questions/14109/two-sided-unique-index-for-two-columns

    【讨论】:

    • 您提供的应用程序级别似乎不起作用,但数据库链接看起来很有用。我会做一些研究,看看 Postgres 的类似解决方案是什么样的。
    • @dyeje 你试过了吗?
    【解决方案2】:

    如果您想在数据库级别验证它,您需要在连接表的两个字段上设置复合索引。更多信息可以在这里找到:How to implement a unique index on two columns in rails

    假设您调用连接表memberships,请尝试以下迁移:

    add_index :memberships, [:relationship_id, :asset_id], unique: true
    

    或者,让 rails 处理验证:

    class Membership < ActionRecord::Base
      validates_uniqueness_of :relationship_id, scope: :membership_id
      ...
    end
    

    更多关于 Rails 验证的阅读: https://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-08
      • 1970-01-01
      • 2011-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多