带有工厂机器人的授权类型,相互依赖的外键问题

发布于 2025-01-25 14:14:56 字数 1895 浏览 1 评论 0原文

我正在尝试弄清楚如何以正确的顺序创建出厂对象,以便委派的类可以访问其父模型。这是我的模型:

class Alert < ApplicationRecord
  delegated_type :alertable, types: %w[QuotaAlert]
  delegate :trigger_percent, :trigger_percent=, :quota, :quota_public_id, to: :quota_alert
  accepts_nested_attributes_for :alertable, update_only: true
module Alertable
  extend ActiveSupport::Concern

  included do
    has_one :alert, as: :alertable, touch: true
    delegate :company, :public_id, :channel, to: :alert
class QuotaAlert < ApplicationRecord
  validates_presence_of :trigger_percent
  validates_inclusion_of :trigger_percent, in: 0..1

  belongs_to :quota

  include Alertable
end

我的工厂:

FactoryBot.define do
  factory :alert do
    company
    channel { 'email' }

    trait :quota_alert_always_trigger do
      before(:create) do |alert|
        alert.alertable = create :quota_alert, trigger_percent: 0
      end
    end

但是,公司的委派委派。我认为我需要更改工厂如何创建对象的顺序,但我无法完全弄清楚正确的顺序。

QuotaAlert需要Alert已经创建以访问alert.company.company,但是,arters没有创建QuotaAlert

实际错误是:模块:: delegationError:QuotaAlert#公司委派给armer.company,但是警报是nil

正确执行此操作的方法是什么?

更新:

# frozen_string_literal: true

FactoryBot.define do
  factory :quota_alert do
    quota { create :quota, :with_random_current_count }
    trigger_percent { rand }
  end
end

更新2: 这是唯一被感动的工厂:

FactoryBot.define do
  factory :quota do
    limit_amount { rand(5000..10_000) }
    name { Faker::Coffee.blend_name }
    feature
    company
    product
    customer
    subscription

    trait :with_random_current_count do
      after(:create) do |quota|
        quota.set_current_count! rand(1..1000)
      end
    end
  end
end

I am trying to figure out how to create Factory objects in the right order so that the delegated class has access to it's parent model. Here are my models:

class Alert < ApplicationRecord
  delegated_type :alertable, types: %w[QuotaAlert]
  delegate :trigger_percent, :trigger_percent=, :quota, :quota_public_id, to: :quota_alert
  accepts_nested_attributes_for :alertable, update_only: true
module Alertable
  extend ActiveSupport::Concern

  included do
    has_one :alert, as: :alertable, touch: true
    delegate :company, :public_id, :channel, to: :alert
class QuotaAlert < ApplicationRecord
  validates_presence_of :trigger_percent
  validates_inclusion_of :trigger_percent, in: 0..1

  belongs_to :quota

  include Alertable
end

And my factory:

FactoryBot.define do
  factory :alert do
    company
    channel { 'email' }

    trait :quota_alert_always_trigger do
      before(:create) do |alert|
        alert.alertable = create :quota_alert, trigger_percent: 0
      end
    end

However, the delegation of company to alert.company is complaining because it says quota_alert.alert is nil. I think I need to change the ordering of how my factory is creating the objects, but I can't quite figure out the right order.

QuotaAlert requires alert to be already created to access alert.company, however, alert can't be created without QuotaAlert.

The actual error is: Module::DelegationError: QuotaAlert#company delegated to alert.company, but alert is nil

What's the right way to do this?

UPDATE:

# frozen_string_literal: true

FactoryBot.define do
  factory :quota_alert do
    quota { create :quota, :with_random_current_count }
    trigger_percent { rand }
  end
end

UPDATE 2:
here's the only other factory that gets touched:

FactoryBot.define do
  factory :quota do
    limit_amount { rand(5000..10_000) }
    name { Faker::Coffee.blend_name }
    feature
    company
    product
    customer
    subscription

    trait :with_random_current_count do
      after(:create) do |quota|
        quota.set_current_count! rand(1..1000)
      end
    end
  end
end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

薄荷港 2025-02-01 14:14:57
# app/models/*.rb

class Company < ApplicationRecord; end
class Quota < ApplicationRecord; end

class Alert < ApplicationRecord
  belongs_to :company

  delegated_type :alertable, types: %w[QuotaAlert]
  # should delegate to `alertable`; otherwise delegated type setup seems unnecessary
  delegate :trigger_percent, :trigger_percent=, :quota, :quota_public_id, to: :alertable

  accepts_nested_attributes_for :alertable, update_only: true
end

class QuotaAlert < ApplicationRecord
  # include Alertable
  has_one :alert, as: :alertable, touch: true
  delegate :company, :public_id, :channel, to: :alert

  belongs_to :quota

  validates :trigger_percent, presence: true, inclusion: { in: 0..1 }
end
# spec/factories/alerts.rb

FactoryBot.define do
  factory :quota
  factory :company

  factory :quota_alert do
    quota
    trigger_percent { 0.2 }
  end

  factory :alert do
    company
    channel { 'email' }
    association :alertable, factory: :quota_alert
  end
end
# spec/fatories_spec.rb

require 'rails_helper'
RSpec.describe "Factories" do
  it { p create(:alert) }
end

您正在调用Company在您的工厂或模型中的某个地方调用记录。创建警报不会单独触发公司委派。

$ rspec spec/factories_spec.rb

Factories
#<Alert id: 1, channel: "email", public_id: nil, company_id: 1, alertable_type: "QuotaAlert", alertable_id: 1>
  example at ./spec/factories_spec.rb:4

Finished in 0.07686 seconds (files took 0.88 seconds to load)
1 example, 0 failures

在控制台中创建警报以确保一切有效,然后将其分解在工厂中可能会更简单。

>> Alert.create!(alertable: QuotaAlert.create!(trigger_percent: 0.1, quota: Quota.create!), company: Company.create!)
# ...
=> #<Alert:0x00007ff608b5acd8 id: 1, channel: nil, public_id: nil, company_id: 1, alertable_type: "QuotaAlert", alertable_id: 1>

让我知道缺少什么。我会更新答案。

# app/models/*.rb

class Company < ApplicationRecord; end
class Quota < ApplicationRecord; end

class Alert < ApplicationRecord
  belongs_to :company

  delegated_type :alertable, types: %w[QuotaAlert]
  # should delegate to `alertable`; otherwise delegated type setup seems unnecessary
  delegate :trigger_percent, :trigger_percent=, :quota, :quota_public_id, to: :alertable

  accepts_nested_attributes_for :alertable, update_only: true
end

class QuotaAlert < ApplicationRecord
  # include Alertable
  has_one :alert, as: :alertable, touch: true
  delegate :company, :public_id, :channel, to: :alert

  belongs_to :quota

  validates :trigger_percent, presence: true, inclusion: { in: 0..1 }
end
# spec/factories/alerts.rb

FactoryBot.define do
  factory :quota
  factory :company

  factory :quota_alert do
    quota
    trigger_percent { 0.2 }
  end

  factory :alert do
    company
    channel { 'email' }
    association :alertable, factory: :quota_alert
  end
end
# spec/fatories_spec.rb

require 'rails_helper'
RSpec.describe "Factories" do
  it { p create(:alert) }
end

You're calling company somewhere in your factories or in the models before the records get created. Creating an alert does not trigger company delegation by itself.

$ rspec spec/factories_spec.rb

Factories
#<Alert id: 1, channel: "email", public_id: nil, company_id: 1, alertable_type: "QuotaAlert", alertable_id: 1>
  example at ./spec/factories_spec.rb:4

Finished in 0.07686 seconds (files took 0.88 seconds to load)
1 example, 0 failures

It might be simpler to create an alert in the console to make sure everything works and then break it down in the factories.

>> Alert.create!(alertable: QuotaAlert.create!(trigger_percent: 0.1, quota: Quota.create!), company: Company.create!)
# ...
=> #<Alert:0x00007ff608b5acd8 id: 1, channel: nil, public_id: nil, company_id: 1, alertable_type: "QuotaAlert", alertable_id: 1>

Let me know what's missing. I'll update the answer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文