2016-09-06 3 views
0
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 

По какой-то причине на производстве я получаюУникальность has_many ассоциации

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

на

self.profiles << profile unless self.profiles.include?(profile) линии.

И после этого у меня есть дубликаты в записях User.profiles.

В чем проблема?

+1

Похоже, что создан новый профиль. Не могли бы вы добавить контекст, в котором возникает ошибка? – mrzasa

+0

Почему вы используете отношения 'has_and_belongs_to_many'? Почему профиль принадлежит многим пользователям? – max

+0

@max, потому что конкретный профиль может принадлежать нескольким пользователям. –

ответ

0

Использование has_and_belongs_to_many, вероятно, не самый лучший вариант здесь.

Если у вас есть довольно распространенный сценарий, когда пользователь может присоединить к своей учетной записи несколько «профилей» или внешних учетных данных 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