FactoryGirl 4.5.0
How do I change the structure of the passed attributes? For example, when working with a large set of existing tests, when serialising existing fields it is desirable for the factory to use the old attributes to make the new models.
Explanation
Given the model Emerald:
# app/models/emerald.rb
class Emerald < ActiveRecord::Base
validates_presence_of :name, :size, :shinyness, :color
end
The factory for Emerald:
# spec/factories/emerald_spec.rb
FactoryGirl.define do
factory :emerald do
sequence(:name) {|n| "Emerald #{n} name"}
size: 12
shinyness: 34
color: 'Dark Green'
end
end
And many rspec tests which do something like:
let(:shiny_emerald) { create(:emerald, attributes: { name: 'Shiny', shinyness: 99 })}
let(:big_emerald) { create(:emerald, attributes: { name: 'Big', size: 888 })}
When serialising some fields on Emerald we get
# app/models/emerald.rb
class Emerald < ActiveRecord::Base
serialize :emerald_properties, Hash
validates_presence_of :name
validates :emerald_properties, emerald_properties: true # This is a custom validator
def size
emerald_properties[:size]
end
def size=(value)
emerald_properties[:size] = value
end
def shinyness
emerald_properties[:shinyness]
end
def shinyness=(value)
emerald_properties[:shinyness] = value
end
def colour
emerald_properties[:colour]
end
def colour=(value)
emerald_properties[:colour] = value
end
end
"Why don't you *do it a different way which might be possible in the limited scope of this example but doesn't apply to any person who might search for this*" aside, what should be done in the factory to allow the existing tests to remain unchanged?
The model still allows you to emerald.size
instead of forcing the use of emerald.emerald_properties[:size]
, I am aiming to achieve the same thing for wielding the factory.
It is a lot of work to do:
let(:big_emerald) { create(:emerald, attributes: { name: 'Big', emerald_properties{ size: 888 }})}
everywhere, aiming to keep
let(:big_emerald) { create(:emerald, attributes: { name: 'Big', size: 888 })}
and adjust it inside the factory.
So far I have:
FactoryGirl.define do
factory :emerald do
sequence(:name) {|n| "Emerald #{n} name"}
emerald_properties ({ {size: 12, shinyness: 34, color: 'Dark Green'}.merge(attributes.slice(*[:size, :shinyness, :color])) })
end
end
but it does not work