Skip to content

Commit

Permalink
fix before_build_callback
Browse files Browse the repository at this point in the history
change the approach for calling the before_build_callback, now it is called before the object is built, and thus called without any attributes
  • Loading branch information
mohammednasser-32 committed Aug 30, 2024
1 parent 4b29329 commit caf7bbc
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 2 deletions.
8 changes: 8 additions & 0 deletions lib/factory_bot/callback.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ def initialize(name, block)
@block = block
end

def run_before_build
syntax_runner.instance_exec(&block)
end

def run(instance, evaluator)
case block.arity
when 1, -1, -2 then syntax_runner.instance_exec(instance, &block)
Expand All @@ -20,6 +24,10 @@ def ==(other)
block == other.block
end

def before_build?
name == :before_build
end

protected

attr_reader :block
Expand Down
7 changes: 7 additions & 0 deletions lib/factory_bot/factory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def build_class
def run(build_strategy, overrides, &block)
block ||= ->(result) { result }
compile
run_before_build_callbacks

strategy = StrategyCalculator.new(build_strategy).strategy.new

Expand Down Expand Up @@ -139,6 +140,12 @@ def compiled_constructor
hierarchy_instance.constructor
end

def run_before_build_callbacks
callbacks.each do |callback|
callback.run_before_build if callback.before_build?
end
end

private

def assert_valid_options(options)
Expand Down
1 change: 0 additions & 1 deletion lib/factory_bot/strategy/build.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ def association(runner)

def result(evaluation)
evaluation.object.tap do |instance|
evaluation.notify(:before_build, instance)
evaluation.notify(:after_build, instance)
end
end
Expand Down
1 change: 0 additions & 1 deletion lib/factory_bot/strategy/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ def association(runner)

def result(evaluation)
evaluation.object.tap do |instance|
evaluation.notify(:before_build, instance)
evaluation.notify(:after_build, instance)
evaluation.notify(:before_create, instance)
evaluation.create(instance)
Expand Down
30 changes: 30 additions & 0 deletions spec/acceptance/callbacks_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,33 @@ def name
expect(build(:company).name).to eq "ACME SUPPLIERS"
end
end

describe "before build callback" do
class TitleSetter
def self.title=(new_title)
@@title = new_title
end

def self.title
@@title
end
end

before do
define_model("Article", title: :string)

FactoryBot.define do
factory :article_with_before_callbacks, class: :article do
before(:build) { TitleSetter.title = "title from before build" }
after(:build) { TitleSetter.title = "title from after build" }

title { TitleSetter.title }
end
end
end

it "runs the before callback" do
article = FactoryBot.build(:article_with_before_callbacks)
expect(article.title).to eq("title from before build")
end
end
11 changes: 11 additions & 0 deletions spec/factory_bot/callback_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,15 @@
FactoryBot::Callback.new(:after_create, ->(one, two) { ran_with = [one, two] }).run(:one, :two)
expect(ran_with).to eq [:one, :two]
end

it "runs run_before_build callback without attributes" do
ran_with = nil
FactoryBot::Callback.new(:before_build, -> { ran_with = "before build" }).run_before_build
expect(ran_with).to eq "before build"
end

it "#before_build?" do
expect(FactoryBot::Callback.new(:before_build, -> {}).before_build?).to be true
expect(FactoryBot::Callback.new(:after_create, -> {}).before_build?).to be false
end
end

0 comments on commit caf7bbc

Please sign in to comment.