Ответ 1
Вот полный рабочий пример:
Файл миграции:
class CreateUserEntities < ActiveRecord::Migration
def change
create_table :user_entities do |t|
t.integer :user_id
t.references :entity, polymorphic: true
t.timestamps
end
add_index :user_entities, [:user_id, :entity_id, :entity_type]
end
end
Модели:
class User < ActiveRecord::Base
has_one :user_entity
has_one :client, through: :user_entity, source: :entity, source_type: 'Client'
has_one :agency, through: :user_entity, source: :entity, source_type: 'Agency'
def entity
self.user_entity.try(:entity)
end
def entity=(newEntity)
self.build_user_entity(entity: newEntity)
end
end
class UserEntity < ActiveRecord::Base
belongs_to :user
belongs_to :entity, polymorphic: true
validates_uniqueness_of :user
end
class Client < ActiveRecord::Base
has_many :user_entities, as: :entity
has_many :users, through: :user_entities
end
class Agency < ActiveRecord::Base
has_many :user_entities, as: :entity
has_many :users, through: :user_entities
end
Как вы можете видеть, я добавил геттер и сеттер, которые я назвал "сущностью". Это потому, что has_one :entity, through: :user_entity
возникает следующая ошибка:
ActiveRecord::HasManyThroughAssociationPolymorphicSourceError: Cannot have a has_many :through association 'User#entity' on the polymorphic object 'Entity#entity' without 'source_type'. Try adding 'source_type: "Entity"' to 'has_many :through' definition.
Наконец, вот те тесты, которые я установил. Я даю им так, чтобы все понимали, что вы можете установить и получить доступ к данным между этими объектами. я не буду подробно описывать свои модели FactoryGirl, но они довольно очевидны
require 'test_helper'
class UserEntityTest < ActiveSupport::TestCase
test "access entity from user" do
usr = FactoryGirl.create(:user_with_client)
assert_instance_of client, usr.user_entity.entity
assert_instance_of client, usr.entity
assert_instance_of client, usr.client
end
test "only right entity is set" do
usr = FactoryGirl.create(:user_with_client)
assert_instance_of client, usr.client
assert_nil usr.agency
end
test "add entity to user using the blind rails method" do
usr = FactoryGirl.create(:user)
client = FactoryGirl.create(:client)
usr.build_user_entity(entity: client)
usr.save!
result = UserEntity.where(user_id: usr.id)
assert_equal 1, result.size
assert_equal client.id, result.first.entity_id
end
test "add entity to user using setter" do
usr = FactoryGirl.create(:user)
client = FactoryGirl.create(:client)
usr.client = client
usr.save!
result = UserEntity.where(user_id: usr.id)
assert_equal 1, result.size
assert_equal client.id, result.first.entity_id
end
test "add entity to user using blind setter" do
usr = FactoryGirl.create(:user)
client = FactoryGirl.create(:client)
usr.entity = client
usr.save!
result = UserEntity.where(user_id: usr.id)
assert_equal 1, result.size
assert_equal client.id, result.first.entity_id
end
test "add user to entity" do
usr = FactoryGirl.create(:user)
client = FactoryGirl.create(:client)
client.users << usr
result = UserEntity.where(entity_id: client.id, entity_type: 'client')
assert_equal 1, result.size
assert_equal usr.id, result.first.user_id
end
test "only one entity by user" do
usr = FactoryGirl.create(:user)
client = FactoryGirl.create(:client)
agency = FactoryGirl.create(:agency)
usr.agency = agency
usr.client = client
usr.save!
result = UserEntity.where(user_id: usr.id)
assert_equal 1, result.size
assert_equal client.id, result.first.entity_id
end
test "user uniqueness" do
usr = FactoryGirl.create(:user)
client = FactoryGirl.create(:client)
agency = FactoryGirl.create(:agency)
UserEntity.create!(user: usr, entity: client)
assert_raise(ActiveRecord::RecordInvalid) {
UserEntity.create!(user: usr, entity: agency)
}
end
end
Надеюсь, это может кому-то помочь. Я решил поставить здесь все решение, потому что это кажется мне хорошим, по сравнению с MTI, и я думаю, что не стоит брать кого-то столько времени, чтобы установить что-то подобное.