What Are Factory_Girl Transient Attributes? Why Would I Use One

What are factory_girl transient attributes? Why would I use one?

factory_bot's transient 'attributes' aren't attributes at all; they're just parameters to the factory method call that can be used by your code inside the factory. So, in your example, no, upcased isn't a model attribute.

The transient block lists 'attribute' names (that is, keys in the hash passed to the factory method) that are not attributes. factory_bot ignores them when setting attributes on the newly created model instance unless you write code in the factory definition to tell factory_bot to do something with them.

evaluator is an object passed to factory_bot callbacks. It's always the second block parameter; the model object is always the first parameter. It's conceptually like Ruby's binding. You can ask it for the value of any key in the argument hash, regardless of whether it's an actual attribute or a transient 'attribute'.

Traits and transient attributes don't affect each other as far as arguments to factory methods are concerned, since traits are scalar and transient attributes are part of the argument hash. Any number of real attributes and transient 'attributes' can be in the argument hash.

Here's the factory_bot documentation for the record: https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md

What is the purpose of a `transient do` block in FactoryBot factories?

transient attributes allow you to pass in data that isn’t an attribute on the model.

Say you have a model called car with the following attributes:

  • name
  • purchase_price
  • model

You want to capitalize the name of the car when you create the car model in the factory. What we can do is:

factory :car do
transient do
# capitalize is not an attribute of the car
capitalize false
end

name { "Jacky" }
purchase_price { 1000 }
model { "Honda" }

after(:create) do |car, evaluator|
car.name.upcase! if evaluator.capitalize
end
end

Hence, whenever you create the car factory and you want to capitalize the name. You can do

car = FactoryGirl.create(:car, capitalize: true)
car.name
# => "JACKY"

Factory Girl - Manipulate Transient Attribute

I was able to find a suitable solution based on the idea presented by Ben. I used a local array variable to store the types of windows that needed to be created. The traits for each window add a type of window to the array in the after(:build) block. Then, in an after(:create) block I actually create the window records.

The very first after(:build) block (the one not in a trait) is important because that resets the window_types array between object creation.

FactoryGirl.define do
window_types = []

factory :house do
floors 3
exterior 'Brick'

after(:build) do
window_types = []
end

after(:create) do |house|
window_types.each do |window_type|
FactoryGirl.create(:window, window_type, house: house)
end
end

trait :with_picture_window do
after(:build) do
window_types << :picture
end
end

trait :with_double_hung_window do
after(:build) do
window_types << :double_hung
end
end

trait :with_bay_window do
after(:build) do
window_types << :bay
end
end

factory :house_with_bay_and_picture_window, traits: [:bay, :picture]
end
end

I'm very curious to hear any thoughts on this approach. For now, this suits my needs and is very flexible.

Factory Girl: Set default value of transient attribute to factory

FactoryGirl.define do
factory :model do
ignore do
zhash
end
numeric_attribute zhash.count
end
end

will not work, but

FactoryGirl.define do
factory :model do
ignore do
zhash
end
numeric_attribute { zhash.count }
end
end

will

(also, "ignore" is deprecated in current factorygirl and is to be replaced by "transient")

Using a transient attribute in before(:create) callback

Defining same_group without a default value causes Factory Girl to treat it as an association rather than an attribute (and attempt to look up a factory of the same name). Changing this line to e.g. same_group nil would solve that problem. It's an admittedly confusing aspect of Factory Girl that the same method can be treated as either an attribute or an association depending on the number of arguments or presence of a block.

FactoryGirl nested transient has_many association with validation

I just saw an upvote on the question, so maybe someone is actually interested in the solution I have for now.

I don't remember exactly where the problem was, but here's a code that works :

# factories/company.rb
FactoryGirl.define do
factory :company do
...

transient do
admins_count 1 # need one admin to pass validation
end

after(:build) do |comp, evaluator|
if evaluator.admins_count == 1
build(:company_admin_user, company: comp)
end
end
end
end

# factories/user.rb
FactoryGirl.define do
factory :user do
...

after(:build) do |user|
user.skip_confirmation!
end

# Company admin
trait(:company_admin) do
transient do
company_admins_count 1
company { build(:company, admins_count: 0) }
end

after(:build) do |user, evaluator|
create_list(:company_admin_profile, evaluator.company_admins_count,
company: evaluator.company,
user: user)
evaluator.company.save
end
end

factory :company_admin_user, traits: [:company_admin]
end
end

# factories/company_admin_profile.rb
FactoryGirl.define do
factory :company_admin_profile, class: CompanyAdminProfile do
...
company
end
end

Undefined method for factory_girl transient attributes

Your ignore/transient block should not have =s

ignore do
jobs_count 2
duration 10
end

Undefined methods for FactoryGirl transient variables

So the solution was to change

transient do
links_count 5
end

to

ignore do
links_count 5
end

Reason: Docs on master are prepared for FactoryGirl v.5.0. transient will wok on 5.0 release.

More reading: http://github.com/thoughtbot/factory_girl/issues/658



Related Topics



Leave a reply



Submit