简体   繁体   English

has_many关联的唯一性

[英]Uniqueness of has_many association

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

For some reason on production I get 由于某种原因,我得到了

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

on

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

And after this I have duplicates in User.profiles records. 之后,我在User.profiles记录中有重复项。

What is the problem? 问题是什么?

Using has_and_belongs_to_many is probably not the best option here. 在这里使用has_and_belongs_to_many可能不是最佳选择。

If you have the quite common scenario where a user may attach several "profiles" or external OAuth credentials to their account you want a one to many relationship. 如果您遇到非常常见的情况,即用户可能将多个“配置文件”或外部OAuth凭据附加到其帐户,则需要一对多关系。

db图

This example uses a generic uid column instead of linkedin_id so that you can use the exact same logic for Facebook, Twitter or any other sort of account. 本示例使用通用uid列而不是linkedin_id以便您可以对Facebook,Twitter或任何其他类型的帐户使用完全相同的逻辑。

class User < ActiveRecord::Base
  has_many :profiles
end


class Profile < ActiveRecord::Base
  belongs_to :user
end

This guarantees that a profile can only belong to a single user. 这样可以保证配置文件只能属于一个用户。 You may want to add some additional uniqueness constraints. 您可能需要添加一些其他的唯一性约束。

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

This enforces on the database level that a user can only have one profile with a given provider and that there may only be one profile with for a given :provider, :uid combination. 这在数据库级别上强制要求,一个用户只能使用一个给定提供者的配置文件,并且对于给定的:provider, :uid组合:provider, :uid可能只有一个配置文件。 Adding indexes in the database safeguards against race conditions and improves performance. 在数据库中添加索引可防止出现竞争情况并提高性能。

You will also want a application level validation to avoid the application crashing due to database driver errors! 您还将需要应用程序级别的验证,以避免由于数据库驱动程序错误而导致应用程序崩溃!

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM