Не могу заставить ИППП действовать как полиморфная ассоциация на модели - PullRequest
0 голосов
/ 02 декабря 2018

У меня есть модель User, которая может иметь адрес электронной почты и номер телефона, обе из которых являются собственными моделями, поскольку обе требуют некоторой формы проверки.

Так что я пытаюсь сделать этоприсоедините Verification::EmailVerification как email_verifications и Verification::PhoneVerification как phone_verifications, которые оба являются STI Verification.

class User < ApplicationRecord
  has_many :email_verifications, as: :initiator, dependent: :destroy
  has_many :phone_verifications, as: :initiator, dependent: :destroy

  attr_accessor :email, :phone

  def email
    @email = email_verifications.last&.email
  end

  def email=(email)
    email_verifications.new(email: email)
    @email = email
  end

  def phone
    @phone = phone_verifications.last&.phone
  end

  def phone=(phone)
    phone_verifications.new(phone: phone)
    @phone = phone
  end
end

class Verification < ApplicationRecord
  belongs_to :initiator, polymorphic: true
end

class Verification::EmailVerification < Verification
  alias_attribute :email, :information
end

class Verification::PhoneVerification < Verification
  alias_attribute :phone, :information
end

Однако, с вышеупомянутой настройкой я получаю ошибку uninitialized constant User::EmailVerification.Я не уверен в том, где я ошибаюсь.

Как я структурирую это так, чтобы я мог получить доступ к email_verifications и phone_verifications на модели User?

1 Ответ

0 голосов
/ 03 декабря 2018

При использовании STI вам не нужны (или не нужны) полиморфные ассоциации.

Полиморфные ассоциации - это хак вокруг проблемы несоответствия объектно-реляционного импеданса, используемой для настройки одной ассоциации, которая указывает на несколько таблиц.Например:

class Video
  has_many :comments, as: :commentable
end

class Post
  has_many :comments, as: :commentable
end

class Comment
  belongs_to :commentable, polymorphic: true
end

Причина, по которой их следует использовать экономно, заключается в том, что нет ссылочной целостности и существует множество проблем, связанных с присоединением и нетерпеливой загрузкой записей, которых нет у STI, поскольку у вас есть "реальный"Столбец внешнего ключа, указывающий на одну таблицу.

STI в Rails просто использует тот факт, что ActiveRecord читает столбец type, чтобы увидеть, какой класс создавать при загрузке записей, который также используется для полиморфных ассоциаций.В противном случае это не имеет ничего общего с полиморфизмом.

Когда вы устанавливаете связь с моделью STI, вам просто нужно создать связь с базовым классом наследования, и рельсы будут обрабатывать разрешение типов, читая столбец типа при загрузке связанных записей:

class User < ApplicationRecord
  has_many :verifications
end

class Verification < ApplicationRecord
  belongs_to :user
end

module Verifications 
  class EmailVerification < ::Verification
    alias_attribute :email, :information
  end
end

module Verifications 
  class PhoneVerification < ::Verification
    alias_attribute :email, :information
  end
end

Вы также должны вкладывать свою модель в модули, а не в классы.Частично это связано с ошибкой в поиске модуля , которая не была устранена до Ruby 2.5, а также с соглашением.

Если вы хотите создать более конкретные ассоциации для подтипов проверки, выможет сделать это:

class User < ApplicationRecord
  has_many :verifications
  has_many :email_verifications, ->{ where(type: 'Verifications::EmailVerification') },
          class_name: 'Verifications::EmailVerification'
  has_many :phone_verifications, ->{ where(type: 'Verifications::PhoneVerification') },
          class_name: 'Verifications::PhoneVerification'
end

Если вы хотите создать псевдоним ассоциации user и назвать ее initiator, вы делаете это, предоставляя опцию имени класса для ассоциации belongs_to и указывая внешний ключ.в has_many ассоциациях:

class Verification < ApplicationRecord
  belongs_to :initiator, class_name: 'User'
end

class User < ApplicationRecord
  has_many :verifications, foreign_key: 'initiator_id'
  has_many :email_verifications, ->{ where(type: 'Verifications::EmailVerification') },
          class_name: 'Verifications::EmailVerification',
          foreign_key: 'initiator_id'
  has_many :phone_verifications, ->{ where(type: 'Verifications::PhoneVerification') },
          class_name: 'Verifications::PhoneVerification',
          foreign_key: 'initiator_id'
end

Это не имеет ничего общего с полиморфизмом.

...