has_many关联的唯一性

时间:2016-09-06 09:02:22

标签: ruby-on-rails activerecord ruby-on-rails-5

class User < ApplicationRecord
  has_and_belongs_to_many :profiles

  def add_profile(profile)
    self.profiles << profile unless self.profiles.include?(profile)
  end
end

class Profile < ApplicationRecord
  has_and_belongs_to_many :users
  validates_uniqueness_of :linkedin_id, allow_nil: true
end

出于某种原因,我得到了

ActiveRecord::RecordInvalid: Validation failed: Linkedin has already been taken

on

self.profiles << profile unless self.profiles.include?(profile)行。

在此之后,我在User.profiles记录中有重复。

有什么问题?

1 个答案:

答案 0 :(得分:0)

使用has_and_belongs_to_many可能不是最佳选择。

如果你有一个很常见的场景,用户可能会附上几个&#34;个人资料&#34;或者您想要一对多关系的帐户的外部OAuth凭证。

Db diagram

此示例使用通用uid列而不是linkedin_id,以便您可以对Facebook,Twitter或任何其他类型的帐户使用完全相同的逻辑。

class User < ActiveRecord::Base
  has_many :profiles
end


class Profile < ActiveRecord::Base
  belongs_to :user
end

这可以保证配置文件只能属于单个用户。您可能希望添加一些额外的唯一性约束。

class AddUserProviderIndexToProfiles < ActiveRecord::Migration
  def change
    add_index(:profiles, [:user_id, :provider], unique: true)
    add_index(:profiles, [:uid, :provider], unique: true)
  end
end

这在数据库级别强制执行,用户只能拥有一个具有给定提供程序的配置文件,并且可能只有一个配置文件具有给定:provider, :uid组合。添加数据库safeguards against race conditions中的索引并提高性能。

您还需要进行应用程序级别验证,以避免因数据库驱动程序错误而导致应用程序崩溃!

class Profile < ActiveRecord::Base
  belongs_to :user
  validates_uniqueness_of :uid, scope: :provider
  validates_uniqueness_of :user_id, scope: :provider
end