【问题标题】:FactoryBot ActiveRecord::AssociationTypeMismatch error with wrong classFactoryBot ActiveRecord::AssociationTypeMismatch 错误类错误
【发布时间】:2020-04-22 03:59:47
【问题描述】:

早上好,

在长时间使用 Rails 之后,我正在开发一个概念验证 Rails 应用程序。我设置了 RSpec 测试,以及 FactoryBot 和 Faker 来生成测试数据。在我的应用中,我有两个模型:

class Admin::Tenant < ApplicationRecord
  has_rich_text :description

  has_and_belongs_to_many :users,
                          association_foreign_key: :admin_user_id,
                          foreign_key: :admin_tenant_id

  has_many :tenant_groups,
           inverse_of: :tenant,
           dependent: :destroy,
           class_name: 'Tenant::Group'

  validates :name,
            presence: true,
            length: { maximum: 255 }
end

class Tenant::Group < ApplicationRecord
  has_rich_text :description

  belongs_to :tenant,
             class_name: 'Admin::Tenant',
             inverse_of: :tenant_groups

  validates :name,
            presence: true,
            length: { maximum: 255 }

  acts_as_tenant :tenant
end

我还定义了两个工厂:

FactoryBot.define do
  factory :admin_tenant, class: 'Admin::Tenant' do
    name { Faker::Lorem.sentence }
  end

  factory :tenant_group, class: 'Tenant::Group' do
    association :tenant, factory: :admin_tenant
    name { Faker::Lorem.sentence }
  end
end

单独使用工厂:admin_tenant 时,它似乎工作正常,但是当我尝试生成:tenant_group(使用create(:tenant_group))时,我在rspec 中收到错误:

     Failure/Error: let(:tenant_group) { create(:tenant_group) }

     ActiveRecord::AssociationTypeMismatch:
       Tenant(#52813860) expected, got #<Admin::Tenant id: 295, name: "Perspiciatis sit numquam fugit.", created_at: "2020-01-03 15:08:13", updated_at: "2020-01-03 15:08:13"> which is an instance of Admin::Tenant(#55283820)

似乎出于某种原因,它假设工厂的类应该是别的东西。由于我在关联中指定了class_name,我认为它会起作用(当我使用应用程序本身时它会起作用)。我看到 Spring 可能会导致问题,所以我按照 FactoryBot README 的建议并将config.before(:suite) { FactoryBot.reload } 放在我的 rails_helper.rb 文件中。

更新 1

现在发现问题在于acts_as_tenant。 RSpec 输出中的堆栈跟踪太短,无法意识到问题所在,但现在它也出现在常规使用中。

更新 2

我将继续并将其标记为已解决。正如我最初认为的那样,这似乎不是 FactoryBot 的问题,而是我对 acts_as_tenant 的理解的问题。当无法通过关联名称轻松推断类名称时,您必须指定:class_name 选项。在浏览了一些源代码之后,这一点变得清晰起来。回想起来,这似乎很明显,因为所有关联的行为方式似乎都相同......

【问题讨论】:

  • 我认为这根本不是 FactoryBot 问题。 FactoryBot 实际上正在做它应该做的事情并创建一个Admin::Tenant 的实例。问题是模型中的关联本身。我没有使用 ActsAsTenant,但我的猜测是 acts_as_tenant :tenant 实际上定义了一个关联,该关联用不带类名选项的关联覆盖 belongs_to :tenant, class_name: 'Admin::Tenant' ...。您可以致电Tenant::Group.reflect_on_association(:tenant) 进行调查。
  • 我认为您的代码看起来不错...有一个快速的谷歌,这些变通办法可能会有所帮助:github.com/thoughtbot/factory_bot/blob/master/…
  • 尝试添加到您的 rspec 配置中:
  • RSpec.configure do |config| config.before(:suite) { FactoryBot.reload } end

标签: ruby-on-rails rspec factory-bot


【解决方案1】:

错误很可能是由ActsAsTenant 引起的,而不是FactoryBot 造成的,因为FactoryBot 正在做正确的事情。

当您创建多个具有相同名称的关联时,后者会覆盖前者。而acts_as_tenant :tenant 就是这样做的,并破坏了您已经建立的关联。它的文档记录不是很好,但the acts_as_tenant macro 采用与belongs_to 大致相同的选项。

class Tenant::Group < ApplicationRecord
  has_rich_text :description
  acts_as_tenant :tenant,
    class_name: 'Admin::Tenant',
    inverse_of: :tenant_groups

  validates :name,
            presence: true,
            length: { maximum: 255 }
end

【讨论】:

  • 谢谢,我更新了我的问题,以便在您回答的同时反映这一点。看来我们得出了同样的结论。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-08
  • 1970-01-01
  • 2023-03-28
  • 2014-07-10
相关资源
最近更新 更多