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
How to Get Ruby-Debug-Ide to Work
Undefined Method 'Devise' When Including User Model Outside Rails
Accessing Headers from Sinatra
How to Run Multiple Lines of Ruby in HTML.Erb File
Running a Shell Command from Ruby: Capturing the Output While Displaying the Output
Generate String for Regex Pattern in Ruby
Why Is Rack Response Body an Array Not a String
How to Properly Test Cancan Abilities with Rspec
How to Completely Remove Webpack and All Its Dependencies from Rails App
Ruby Metaprogramming, How Does Rspec's 'Should' Work
What's the Easiest Way to Send a Message Through Outlook with Ruby
Using Authlogic_API for Rails Rest API Access
How to Run Ruby in Haml in JavaScript Definition