При использовании 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
Это не имеет ничего общего с полиморфизмом.