【问题标题】:Uniqueness of has_many associationhas_many 关联的唯一性
【发布时间】:2016-09-06 09:02:21
【问题描述】:
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

self.profiles &lt;&lt; profile unless self.profiles.include?(profile) 行。

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

有什么问题?

【问题讨论】:

  • 看起来新的配置文件已创建。您能否添加引发错误的上下文?
  • 您为什么使用has_and_belongs_to_many 关系?为什么个人资料会属于许多用户?
  • @max 因为特定的配置文件可以属于多个用户。

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


【解决方案1】:

在这里使用has_and_belongs_to_many 可能不是最好的选择。

如果您有一个非常常见的场景,即用户可能会将多个“配置文件”或外部 OAuth 凭据附加到他们的帐户,您需要一对多的关系。

此示例使用通用 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-12
    • 2018-03-08
    • 2016-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多