I am using factory_girl 4.2.0 (not factory_girl_rails) with rails 4.0.0.rc1 and sequel 3.46.0.
Given these factory definitions:
factory :user do
username { generate :username }
provider_id { generate :provider_id }
provider 'soundcloud'
end
sequence :username do |i|
Faker::Internet.user_name + i.to_s
end
sequence :provider_id do |i|
Faker::Address.zip + i.to_s
end
When I build a user without passing any attributes, it works as expected:
puts build(:user).inspect # => #<User @values={:username=>"dana1", :provider_id=>"884101", :provider=>"soundcloud"}>
And when I provide certain attributes, say :username, it still works as expected:
puts build(:user, username: 'Alex').inspect # => #<User @values={:username=>"Alex", :provider_id=>"628062", :provider=>"soundcloud"}>
However, when I provide provider or provider_id, the other is discarded:
puts build(:user, provider: 'twitter').inspect # => #<User @values={:username=>"adella.hyatt2", :provider=>"twitter"}>
puts build(:user, provider_id: '1234').inspect # => #<User @values={:username=>"camron3", :provider_id=>"1234"}>
The issue arose because I have not null constraints on provider and provider_id columns, which were raising SQL exceptions when calling #create.
Here is my user table schema:
DB.create_table :users do
primary_key :user_id
String :provider_id, null: false
String :provider, null: false
String :username, null: false
index [:provider_id, :provider], unique: true
end
And there are no validations/callbacks on the User model.
Won't be at all surprised if the bug is on my end, but I haven't been able to track anything down yet.
Thanks for your help!
Also, I'm monkey-patching Sequel::Model
to allow FactoryGirl to call #save!
:
Sequel::Model.send :alias_method, :save!, :save
Unless there is a way to configure FactoryGirl to use #save
instead of #save!
, you will have to do this as well to reproduce the issue.
@alexgenco we actually have some logic in FG to treat {name} and {name}_id as the same column and strip it out manually. This is done with an array: FactoryGirl.aliases
. If you clear this array, it should resolve the issue, but the caveat is that other things may break (a lot depends on how you've structured your DB/models). I'd reconsider how you've set up your database - either by using provider_id
/provider_name
or just creating a Provider model, table, and leaving provider_id as a FK on users.
As for the save!
issue, you can actually override to_create
for all of your models:
FactoryGirl.define do
to_create { |instance| instance.save }
factory :foo do
# ...
end
factory :bar do
# ...
end
end
Ah, fair enough. provider_name it is, then. And sorry, I must have missed to_create
in the docs.
Thanks again!
@alexgenco no problem, and no worries about the to_create
!
For anyone finding this, the other option if you can't rename your columns is to set alias
up to simply ignore that particular match like so:
FactoryGirl.aliases = [
[/([^(?:provider)].+)_id/, '\1'],
[/([^(?:provider)].*)/, '\1_id'],
]
This worked well for us. That should match everything except for provider
and provider_id
attributes.
Most helpful comment
@alexgenco we actually have some logic in FG to treat {name} and {name}_id as the same column and strip it out manually. This is done with an array:
FactoryGirl.aliases
. If you clear this array, it should resolve the issue, but the caveat is that other things may break (a lot depends on how you've structured your DB/models). I'd reconsider how you've set up your database - either by usingprovider_id
/provider_name
or just creating a Provider model, table, and leaving provider_id as a FK on users.As for the
save!
issue, you can actually overrideto_create
for all of your models: