Search code examples
ruby-on-railsactiverecordrspecassociationsfactory-bot

How to prevent ActiveRecord from making an associated record in a callback before it is saved?


I have two models, Branch and Organization. An organization has many branches. A branch cannot exist without an associated organization, and an organization cannot exist without at least one branch. In the organization model, we have the following:

  after_create :create_branch_if_not_exists!
...
  def create_branch_if_not_exists!
    return unless branches.empty?

    branch = Branch.new(attrs: some_attrs)
    branches << branch
  end

Turns out this is a problem when testing, because when creating a branch, we actually create two. Using FactoryBot:

FactoryBot.define do
  factory :branch do
    organization
    ...
  end
end

# in test
create(:branch) # this creates two branches.

Before the branch is created, I guess the organization is created? And its after_create method doesn't know about the branch that is about to be created, so it goes ahead and creates one first.

There are many tests, it would be many changes to always create organizations first.

Is there an easy workaround? Or am I just structuring my code poorly or what?

Tried changing to after_commit but same thing.


Solution

  • It sounds like the code and test logic contradict. Test should rely on the code behavior.

    What will the actual code do when it needs to create a branch? probably same as test, will also create an organization and another branch. Is this a valid scenario?

    Anyway, if you're sure about the business logic you can try to skip the after_create callback in your tests as described here:

    Organization.skip_callback(:create, :after, :create_branch_if_not_exists!)
    

    You can set back the callback when you're done using:

    Organization.set_callback(:create, :after, :create_branch_if_not_exists!)