Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FactoryBot/FactoryAssociationWithStrategy cop error when something is defined in a transient #61

Open
schinery opened this issue Jul 14, 2023 · 4 comments

Comments

@schinery
Copy link

Not sure if this is related to #54 but the issue I am having is that when something has been defined in a transient block that is using build or create, then rubocop throws a FactoryBot/FactoryAssociationWithStrategy error thinking it is an association.

For example this:

# frozen_string_literal: true

FactoryBot.define do
  factory :visit, class: "Visit" do
    transient do
      address { build(:address) }
    end

    visitable factory: %i[job]

    before(:create) do |visit, evaluator|
      visit.visitable.address = evaluator.address 
    end
  end
end

Leads to this:

spec/factories/visits.rb:6:17: C: FactoryBot/FactoryAssociationWithStrategy: Use an implicit, explicit or inline definition instead of hard coding a strategy for setting association within factory.
      address { build(:address) }

I know in this example I could get around this by changing the above code to address { nil } and evaluator.address || build(:address) but I have some other factories doing the same that aren't so straightforward to amend.

Rubocop Gems:

 bundle exec gem list rubocop

*** LOCAL GEMS ***

rubocop (1.54.2)
rubocop-ast (1.29.0)
rubocop-capybara (2.18.0)
rubocop-factory_bot (2.23.1)
rubocop-faker (1.1.0)
rubocop-rails (2.20.2)
rubocop-rake (0.6.0)
rubocop-rspec (2.22.0)
@schinery schinery changed the title FactoryBot/AssociationStyle.EnforcedStyle cop error when something is defined in a transient FactoryBot/FactoryAssociationWithStrategy cop error when something is defined in a transient Jul 15, 2023
@pirj
Copy link
Member

pirj commented Jul 15, 2023

What does the build(:address) do exactly?

@schinery
Copy link
Author

What does the build(:address) do exactly?

If the visit factory is created without supplying an address to it, so create(:visit) rather than create(:visit, address: some_address_object), then it will build a default address using the address factory, and set it as the visit's visitable address.

This is to save passing a visitable object with a known address object attached to the factory each time we want to create a visit object and do stuff with the address in specs.

@pirj
Copy link
Member

pirj commented Jul 15, 2023

Is address a model and an association in visits model?

@schinery
Copy link
Author

Is address a model and an association in visits model?

No, it is an association on the visit's visitable object, in this case a job. The job will have something like:

class Job
  has_one :address
  has_many :visits, as: :visitable
end
FactoryBot.define do
  factory :job, class: "Job" do
    address factory: %i[address]
  end
end

Then let's say we had a spec doing something like this:

let!(:visit) { create(:visit, address: build(:address, postcode: "W1 1TX")) }

before do
  create(:visit, address: build(:address, postcode: "NW1 2ED"))
end

# Return all the visit's who's visitable (job) postcode matches
it { expect(Visit.by_visitable_postcode("W1 1TX")).to eq([visit]) }

Setting the address in the transient and applying to the visitable in the before(:create) saves us having to do the following in every spec that needs a visit with a specific address...

let!(:visit) do
  job = create(:job, address: build(:address, postcode: "W1 1TX"))
  create(:visit, visitable: job) 
end

before do
  job = create(:job, address: build(:address, postcode: "NW1 2ED"))
  create(:visit, visitable: job)
end

it { expect(Visit.by_visitable_postcode("W1 1TX")).to eq([visit]) }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants