Rails 3 Validations - Association Properties, RSpec, and Factory Girl - ruby-on-rails

I'm trying to write a validation class in rails 3 that will check for the presence of at least one associated object that has a particular property value.
In my scenario, an Account can have many Users. The User model has a "Role" string field. An account must have at least one User with a Role that equals "admin".
The following code is breaking during my testing (I'm using rspec & Factory Girl). When the tests are executed, the account_id is returning as null.
Here is the model:
class Account < ActiveRecord::Base
validates :name, :presence => true, :uniqueness => true
validate :has_one_admin
has_many :users
attr_accessible :name
private
def has_one_admin
User.where(:role => "admin", :account_id => self.id).count > 0
end
end
Here is the error being thrown by rspec:
Error message being thrown: Failure/Error: #account = Factory(:account_with_admin)
ActiveRecord::StatementInvalid:
SQLite3::SQLException: no such column: users.account_id: SELECT COUNT(*) FROM "users" WHERE "users"."role" = 'admin' AND "users"."account_id" IS NULL
Here is the RSpec test:
require 'spec_helper'
describe Team do
# - Removed -
# before(:each) do
# #account = Factory(:account)
# #attr = { :name => "Testing Team"}
# end
# Modified after discussion...
before(:each) do
#user = Factory(:user)
#act_attr = { :name => "My Account",
:users => #user }
#account = Account.new(#act_attr)
#attr = { :name => "Testing Team"}
end
# End of modification
it "must have a name" do
no_name_team = Team.new(#attr.merge(:name => ""))
no_name_team.should_not be_valid
end ...
And finally, my factory file:
Factory.define :admin, :class => User do |f|
f.email 'admin#admin.com'
f.password 'password'
f.role 'admin'
end
Factory.define :team, :class => Team do |f|
f.name 'Testing Team'
end
Factory.define :account, :class => Account do |f|
f.name 'Testing Account'
end
Factory.define :account_with_admin, :parent => :account do |f|
f.after_create { |a| Factory(:admin, :account => a) }
end
My assumption is that I'm jumping ahead of the persisting of the object somewhere but I'm just not sure where. Thanks for any help / direction!

Related

Rails 3 - Factory girl and sequence for belongs_to table

I have 2 models - User and Teacher. Teacher belongs_to User, User has Teacher.
So, i use Factory girl gem:
Factory.define :user do |user|
user.user_login "Another User"
user.user_role "admin"
user.password "foobar"
end
Factory.sequence :user_login do |n|
"person-#{n}"
end
Factory.define :teacher do |teacher|
...
teacher.user
end
I met problem and i don't understand how to solve that. When i create user via factory i can easily write:
#user = Factory( :user, :user_login => Factory.next(:user_login) )
And this creates user with inique login.
How can i do same thing for teacher? I tried that:
#teacher = Factory( :teacher, :user_login => Factory.next(:user_login) )
And it doesn't work.
You don't have to specify sequences separately and then pass them to another factory - you can use them inside factories like this:
Factory.define :user do |user|
# ...
user.sequence(:user_login) { |n| "person=#{n}" }
end
or shorter
Factory.define :user do
# ...
sequence(:user_login) { |n| "person=#{n}" }
end
Then, to association a user with teacher:
Factory.define :teacher do
association :user
end
Then you can just call
#teacher = Factory(:teacher)
which will automatically create the associated user with the next user_login in the sequence.
I solved that.
#teacher = Factory( :teacher,
:user => Factory(:user, :user_login => Factory.next(:user_login)) )

Validation error on associated factory when using FactoryGirl with RSpec

I'm new to using RSpec and FactoryGirl. I'm trying to add RSpec tests to an existing codebase.
I have the following factories defined:
Factory.sequence :email do |n|
"somebody#{n}#example.com"
end
Factory.sequence :login do |n|
"inquire#{n}"
end
Factory.define :user do |f|
f.login { Factory.next(:login) }
f.email { Factory.next(:email) }
f.password 'inquire_pass'
f.password_confirmation 'inquire_pass'
f.first_name 'test'
f.last_name 'guy'
f.newsletter true
f.notify_of_events true
f.terms_of_service true
end
Factory.define :project do |project|
project.title "Example Project Title"
project.association :user
project.association :provider
project.association :project_request
project.association :offering
project.association :offering_type
end
When I try to create a Project factory in my tests, however and assign it to #project:
require 'spec_helper'
describe Charge do
before(:each) do
#provider_user = Factory(:user)
#provider = stub_model(Provider, :user => #provider_user)
#user = Factory(:user)
#project_request = stub_model(ProjectRequest)
#project = Factory(:project, :user => #user, :provider => #provider, :offering_fixed_fee_number => 700,
:project_request_id => #project_request.id)
#attr = {
:user_id => #user.id,
:provider_id => #provider.id,
:charge_client => "0.01"
}
#charge = #project.build_charge(#attr)
end
I get an error message when running the tests indicating that the validations for the associated user have failed:
Validation failed: User email can't be blank, User email is too short (minimum is 3 characters), User email does not look like a valid email address., Login can't be blank
The relevant validations on the User model are:
validates_presence_of :login, :email
validates_uniqueness_of :login, :email, :case_sensitive => false
validates_length_of :login, :within => 5..20
validates_format_of :login, :with => /^[a-z0-9-]+$/i, :message => 'may only contain letters, numbers or a hyphen.'
validates_length_of :email, :within => 3..100
validates_format_of :email, :with => Authentication.email_regex, :message => 'does not look like a valid email address.'
I'm able to create valid User factories (by themselves) with no problem. But when I try to create projects that have a User association, and specify the associated User as the factory user I created earlier, the validations on that User fail. Any ideas what I'm missing here?
Thanks very much,
Dean Richardson
Maybe it's because factory param in association method is missing:
Factory.define :project do |project|
project.association :user, :factory => :user
...
end
But in this case it could be written more easily:
Factory.define :project do |project|
project.user
...
end
See Factory Girl. Getting Started

Trouble on initializing a factory object

I am using Ruby on Rails 3.1.0, rspec-rails 2 and Factory gems. I have some trouble related to the validation process when I state a Factory object for an Account class.
In the model file I have:
class Account < ActiveRecord::Base
belongs_to :user
attr_accessible :name, ..., :password
validates :name,
:presence => true
...
validates :password,
:presence => true
end
In the factory file I have:
FactoryGirl.define do
factory :account, do
sequence(:name) { |n| "Foo #{n}"}
...
password 'psw_secret'
association :user
end
factory :user do
auth 'registered'
end
end
When in the spec file I state let!(:account) { Factory(:account) } it works as expected but when I use the following:
let!(:user) { Factory(:user, :account => Factory(:account)) }
I get this error:
Failure/Error: let!(:user) { Factory(:user, :account => Factory(:account)) }
ActiveRecord::RecordInvalid:
Validation failed: Account password can not be blank, Account is invalid
Why I get that error? How can I solve the problem?
I think you should do it the other way around:
#user = Factory(:user)
#account = Factory(:account, :user => #user)
The relation is defined on account, not on user.
Hope this helps.

Rspec + Factory Girl First Example works, 2nd+ do not

I have an spec like so:
require 'spec_helper'
describe IncomingMailsController do
include Devise::TestHelpers
before(:each) do
#user = Factory.create(:user)
#user1 = Factory.create(:user)
#group = Factory(:group)
#perm1 = Factory.create(:permission, :user => #user)
#perm2 = Factory.create(:permission, :user => #user1)
end
it "xxxxx case 1" do
....
end
it "xxxxx case 2" do
....
end
The first case 1, works fine but then the 2nd fails with:
Failure/Error: #perm1 = Factory.create(:permission, :user => #user)
RuntimeError:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
# ./spec/factories.rb:23
Does the before each run fresh for each it block?
factories.rb looks like:
require 'factory_girl'
Factory.define :user do |f|
f.sequence(:fname) { |n| "fname#{n}" }
f.sequence(:lname) { |n| "lname#{n}" }
f.sequence(:email) { |n| "email#{n}#google.com" }
f.password "password"
f.password_confirmation { |u| u.password }
f.invitation_code "dmbsrv82811"
end
Factory.define :group do |f|
f.name "myGroup"
f.sequence(:private_email) { |n| "myGroup#{n}" }
end
Factory.define :permission do |f|
f.role_id 1
f.group_id do
(Group.find_by_name('myGroup')).id
end
f.creator_id do
(User.find_by_fname('fname1')).id
end
end
Thanks
On line 23 of factories.rb you have
(User.find_by_fname('fname1')).id
This is hardcoded to find fname1. However, your factory uses a sequence to define fname:
f.sequence(:fname) { |n| "fname#{n}" }
This means that in the second spec, the value for fname will be fname2, not fname1. This is because sequences aren't reset between different specs.
All of this means that when you call User.find_by_fname, it can't find a user with fname1 (only fname2), so it returns nil, which is why you get the called id for nil error.
-- Edit --
Are you doing anything with the user attribute you pass in to the permission factory (for eg with Factory.create(:permission, :user => #user))? If not, I'd change it to something like
Factory.create(:permission, :creator => #user)
Note: if you don't have Permission#creator setup as an association with User you'll need to rather do
Factory.create(:permission, :creator_id => #user.id)
On a similar vein, you might want to define your factory more along the lines of
Factory.define :permission do |f|
f.role_id 1
f.association :group, :factory => :group
f.association :creator, :factory => :user
end
If your associations are setup correctly, there's no need to worry about the ids, the association does the Right Thing for you.

Dependent Attributes in Factory Girl

Seems like I should have been able to find an obvious answer to this problem after a few hours of Googling and testing.
I want to be able to set caredate.user_id => provider.user_id within the caredate factory.
Test Error:
ActiveRecord::RecordInvalid:
Validation failed: User must be same
as provider user
I have an ActiveRecord validation which works when tested via the browser:
class Caredate < ActiveRecord::Base //works fine when testing via browser
belongs_to :user
belongs_to :provider
validates_presence_of :user_id
validates_presence_of :provider_id
validate :user_must_be_same_as_provider_user
def user_must_be_same_as_provider_user
errors.add(:user_id, "must be same as provider user") unless self.user_id == self.provider.user_id
end
end
//factories.rb
Factory.define :user do |f|
f.password "test1234"
f.sequence(:email) { |n| "foo#{n}#example.com" }
end
Factory.define :caredate do |f|
f.association :provider
**f.user_id { Provider.find_by_id(provider_id).user_id } //FAILS HERE**
end
Factory.define :provider do |f|
f.association :user
end
My apologies if this has been answered previously; I tried several different options and couldn't get it to work.
Update: This passes validation, so I'm getting closer. I could hack with a random number.
Factory.define :caredate do |f|
f.association :user, :id => 779
f.association :provider, :user_id => 779
end
Factory.define :caredate do |f|
provider = Factory.create(:provider)
f.provider provider
f.user provider.user
end
Try setting the user_id in after_create or after_build:
Factory.define :caredate do |f|
f.after_create { |caredate| caredate.user_id = caredate.provider.user_id }
end

Resources