gpt4 book ai didi

ruby-on-rails - 多表继承上的 has_one 和多态关联

转载 作者:行者123 更新时间:2023-12-04 00:58:47 25 4
gpt4 key购买 nike

在我目前正在 Rails 4.0.0beta1 下开发的项目中,我需要基于用户的身份验证,其中每个用户都可以链接到一个实体。我对 Rails 有点陌生,这样做时遇到了一些麻烦。

模型如下:

class User < ActiveRecord::Base
end

class Agency < ActiveRecord::Base
end

class Client < ActiveRecord::Base
belongs_to :agency
end

我需要的是让用户能够链接到代理机构或客户,但不能同时链接到两者(我将称之为实体)。它可以完全没有链接,最多只有一个链接。

我寻找的第一件事是如何在 rails 中执行 Mutli-Table inheritance (MTI)。但有些事情阻止了我:
  • 它不是开箱即用的
  • 对于像我这样的新手来说,MTI 看起来有点难以实现
  • 实现解决方案的 gems 看起来很旧,要么太复杂,要么不完整
  • gems 可能会在 rails4 下损坏,因为它们有一段时间没有更新

  • 所以我寻找了另一个解决方案,我找到了 polymorphic associations

    我从昨天开始就在做这个,即使在 Rails polymorphic has_many :throughActiveRecord, has_many :through, and Polymorphic Associations 的帮助下,我也花了一些时间让它工作

    我设法使上述问题中的示例起作用,但花了一段时间,最后我遇到了两个问题:
  • 如何将用户中的关系转换为 has_one 关联并能够“盲目”访问链接实体?
  • 如何设置约束,使用户不能拥有多个实体?
  • 有没有更好的方法来做我想做的事?
  • 最佳答案

    这是一个完整的工作示例:

    迁移文件:

    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

    如您所见,我添加了一个名为“entity”的 getter 和 setter。那是因为 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 相比,它在我看来是一个很好的解决方案,我认为不应该花太多时间来设置类似的东西。

    关于ruby-on-rails - 多表继承上的 has_one 和多态关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15416528/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com