Most of this was fixed by adding the `attribute-defined-statically-cop`
branch of `thoughtbot/rubocop-rspec` to the Gemfile and running:
```sh
rubocop \
--require rubocop-rspec \
--only FactoryBot/AttributeDefinedStatically \
--auto-correct
```
I had to update the cucumber tests manually, and I realized our changes
don't handle `ignore` blocks or blocks with arity 1 that use the yielded
DefinitionProxy. I will update
https://github.com/rubocop-hq/rubocop-rspec/pull/666to handle these
cases.
* Update callbacks spec so column types reflect assignment
Rails 4.2 introduces type coercion on attribute assignment instead of it
occurring after persisting the record.
This allows callbacks (after :build, :create, etc.) to be defined at the
FactoryGirl level; this means that the callback will be invoked for all
factories. This is primarily to maintain consistency and follow the
principle of least surprise.
As usual, callbacks are applied from the lowest component to the
highest, meaning that global callbacks will be run after factory and
trait callbacks are run.
FactoryGirl.define do
after(:build) {|object| puts "Built #{object}" }
factory :user
# ...
end
Closes#481Closes#486
This allows for binding multiple callbacks (after_stub, before_create,
etc.) to a single block. This is useful if you want a block to be called
across all build strategies (since build_stubbed doesn't share any
callbacks with build/create).
Examples:
factory :user do
callback(:after_stub, :before_create) { do_something }
after(:stub, :create) { do_something_else }
before(:create, :custom) { do_a_third_thing }
end
Instead of calling before_create, after_build, after_create, or
after_stub, you can now call:
before(:create) {|instance| instance.name = "overridden!" }
after(:create) {|instance| instance.name = "overridden!" }
after(:build) {|instance| instance.name = "overridden!" }
after(:stub) {|instance| instance.name = "overridden!" }
Additionally, you can declare callbacks longhand:
callback(:after_stub) {|instance| instance.name = "overridden!" }
This allows for custom callbacks to be defined:
callback(:custom_callback) {|instance| instance.name = "overridden!" }
Which can then be used from a custom strategy:
class CustomStrategy
def association(runner); end
def result(evaluation)
evaluation.object.tap do |instance|
evaluation.notify(:custom_callback, instance)
end
end
end
FactoryGirl.register_strategy(:custom, CustomStrategy)
This would allow for calling:
FactoryGirl.custom(:user)
Which would return the user instance but execute the :custom_callback callback
on the user instance first.