FactoryGirl belongs_to with Seeded association - ruby-on-rails-3

I have a UserType object that ideally is seeded in the DB and remains static:
{id: 1, name: 'Individual'}, {id: 2, name: 'Group'}, {id: 3, name: 'Admin'}
class UserType < ActiveRecord::Base
attr_accessible :name
has_many :users
end
class User < ActiveRecord::Base
attr_accessible :email, :first_name
belongs_to :user_type
end
In testing, I simply want to create an admin user that has its user_type_id field set to 3 when created, and for the UserType.all to have those three items. I've tried a number of things, but here's where I'm at:
FactoryGirl.define do
factory :user_type do
id 1
name "Individual"
trait :group do
after(:create) do |user_type|
id 2
name "Group Leader"
end
end
trait :admin do
after(:create) do |user_type|
id 3
name "Administrative"
end
end
end
end
FactoryGirl.define do
factory :user do
first_name 'TestUser'
email { Faker::Internet.email }
user_type
trait :admin do
after(:create) do |user|
admin_user_type = UserType.where(id: 3).first
admin_user_type = create(:user_type, :admin) unless admin_user_type
user_type admin_user_type
end
end
end
And my test in spec/features/sessions/admin_sign_in_spec.rb:
feature "Admin signing in" do
background do
#institution = create(:institution_with_institutiondomains)
#admin = create(:user, :admin, email: "admin##{#institution.subdomain}.com")
end
scenario "with correct credentials", focus: true do
binding.pry
#admin.inspect
page.visit get_host_using_subdomain(#institution.subdomain)
within("#login-box") { fill_in t('email'), with: #admin.email }
click_button t('session.admin.sign_in') #the action in signing in here checks that user.user_type_id == 3
expect(page).to have_content "You're signed in!"
end
end
In many cases, especially in tests where I have multiple users getting created, I'll receive a MySQL duplicate error on the first id: 1 Individual. I appreciate any guidance.

For what it's worth, anyone finding this may not like my answer, but it is the only thing that works for me. UserTypes are static in my test database, so I removed the traits in the :user_type factory. Instead, I simply set the user_type_id directly and call save on it. Without the save, the change does not persist to my #admin variable. The test data is cleaned between tests using DatabaseCleaner, leaving my user_types table alone.
FactoryGirl.define do
factory :user do
first_name 'TestUser'
email { Faker::Internet.email }
user_type
trait :admin do
after(:create) do |user|
# admin_user_type = UserType.where(id: 3).first
# admin_user_type = create(:user_type, :admin) unless admin_user_type
# user_type admin_user_type
user.user_type_id = 3
user.save #without this, the change won't persist
end
end
end
end

Related

FactoryGirl, 2 times creates user?

I really dont understand of making assotiations. In spec_helper I have got
def log_in_user
user = User.find_by_name 'User1'
user = FactoryGirl.create :user1 unless user
sign_in user
end
in rspec
let(:product) { FactoryGirl.build :product_A }
describe "GET confirm purchase" do
it "xxx" do
log_in_user
Product.should_receive(:find_active_by_id).with("1").and_return(product)
...
end
end
factories.rb
FactoryGirl.define do
factory :user do
encrypted_password 'abcdef1'
confirmed_at Time.now
factory :user1 do
email 'user1#test.com'
name 'User1'
year 1984
end
end
factory :product do
factory :product_A do
name "product A"
association :user, factory: :user1
end
end
end
when I run test case an exception occures:
ActiveRecord::RecordInvalid: Validation failed: Email has already been taken
It looks like user1 is creating 2 times, one in log_in_user and the second one in factory: association :user, factory: :user1
I am right? If yes, how can I solve this? I want to create user and have assotiation defined in factory product
best
When you factory :product_A it is automatically calling the factory for :user1.
Then you factory :user1 again in the log_in_user, but the validation on unique emails is preventing the second :user1 from being created.
I would recommend you make email a sequence like so:
FactoryGirl.define do
sequence :email do |n|
"user#{n}#test.com"
end
factory :user do
encrypted_password 'abcdef1'
confirmed_at Time.now
factory :user1 do
email
name 'User1'
year 1984
end
end
factory :product do
factory :product_A do
name "product A"
association :user, factory: :user1
end
end
end
Then, I would alter the sign_in_user to take an (optional) user as an option like this:
def log_in_user(user)
user =|| User.find_by_name 'User1'
user =|| FactoryGirl.create :user1
sign_in user
end
And modify your test case to pass that user object to the login:
let(:product) { FactoryGirl.build :product_A }
describe "GET confirm purchase" do
it "xxx" do
log_in_user(product.user)
Product.should_receive(:find_active_by_id).with("1").and_return(product)
end
end

What things do I need to know when creating model from another controller and mass-assignment

I have a model called DefaultCompany that has no controller, instead I create it through the companies_controller which calls the user.set_default_company (defined below) if they check the "default company" checkbox on the form.
Default company is a joining table of user_id and company_id.
class DefaultCompany < ActiveRecord::Base
attr_accessible :company_id, :user_id
belongs_to :company
belongs_to :user
end
I keep getting the following error:
Can't mass-assign protected attributes: company, user
app/models/user.rb:22:in `set_default_company'
app/controllers/companies_controller.rb:23:in `create'
I've set my user model to be able to accept nested attributes for DefaultCompany, like this
class User < ActiveRecord::Base
has_one :default_company
accepts_nested_attributes_for :default_company
attr_accessible :default_company_attributes
def set_default_company(company)
exists = DefaultCompany.find(self.id)
if exists
exists.update_attributes(company: company)
else
DefaultCompany.create(company: company, user: self)
end
end
end
And here is the create action for the companies_controller.rb
def create
#company = Company.new(params[:company])
if #company.save
if params[:default_company]
current_user.set_default_company #company.id
end
flash[:notice] = "Company was successfully created."
Role.assign_creator(#company.id, current_user.id)
redirect_to #company
else
redirect_to new_company_path
end
end
So I'm not sure what I need to add so that mass-assignment will pass, can anyone help me figure out / explain this?
I believe rails is strict about the naming in mass-assignment, so although you've whitelisted company_id and user_id, you have not whitelisted company and user.
Try changing the assignment in set_default_company to:
if exists
exists.update_attributes(company_id: company.id)
else
DefaultCompany.create(company_id: company.id, user_id: self.id)
end
You can either change the attr_accessible attributes on Company to :user and :company or set :company_id and :user_id in your set_default_company method call.
Edit:
exists = DefaultCompany.find(self.id)
This seems to be wrong according to your logic.

Rail 3.2.2/Devise: deprecation warning with rspec

I recently upgraded an app to rails 3.2.2.
I'm using Factory_girl
Factory.sequence :name do |n| "name-#{n}" end
Factory.define :user do |u| u.first_name{ Factory.next(:name) }
u.last_name { |u| 'last_' + u.first_name } u.password 'secret'
u.password_confirmation { |u| u.password } u.sequence(:email) { |i|
"user_#{i}#example.com" }
end
and this simple test
specify { Factory.build(:user).should be_valid }
generate the following warning
DEPRECATION WARNING: You're trying to create an attribute user_id'.
Writing arbitrary attributes on a model is deprecated. Please just use
attr_writer` etc. (called from block (2 levels) in
at...
How can I get rid of it?
It's probably because you haven't prepared/migrated your test database with updated column definitions, thus it thinks you're trying to arbitrarily set the attribute.
Run rake db:test:prepare to make sure it's updated.
Here's the source code of that method, where you can see Rails checks for the column or attribute first, then warns if they're not found.
I've met the same warning with the following code:
Ad model:
class Ad < ActiveRecord::Base
belongs_to :user
end
Factories:
FactoryGirl.define do
factory :ad do
association :user
end
end
FactoryGirl.define do
factory :user do
first_name {Factory.next(:first_name)}
last_name {Factory.next(:last_name)}
email {|x| "#{x.first_name}.#{x.last_name}#{Factory.next(:count)}#test.com"}
password Forgery(:basic).password
confirmed_at Date.today << 10
end
end
Test
require 'spec_helper'
describe Ad do
before(:each) do
#ad = Factory.build(:ad)
end
"it is not valid without a user"
end
Running the test gave me a similar error.
Adding
attr_accessor :user
to the Ad model fixed the warning.
I hope it helps.
I had this same warning while doing tests in Rspec and my issue was that I had a Parent model and Child model where I accidentally had this:
class Child < ActiveRecord::Base
belongs_to :parent
end
......
class Parent < ActiveRecord::Base
belongs_to :child
end

Ruby on Rails 3: has_one association testing

I may have my associations messed up. I have the following models: User and UserProfiles.
My models:
class User < ActiveRecord::Base
has_one :user_profile, :dependent => :destroy
attr_accessible :email
end
class UserProfile < ActiveRecord::Base
belongs_to :user
end
I have a column named "user_id" in my user_profiles table.
My factory is setup like so:
Factory.define :user do |user|
user.email "test#test.com"
end
Factory.sequence :email do |n|
"person-#{n}#example.com"
end
Factory.define :user_profile do |user_profile|
user_profile.address_line_1 "123 Test St"
user_profile.city "Atlanta"
user_profile.state "GA"
user_profile.zip_code "30309"
user_profile.association :user
end
My user_spec test is setup like so:
describe "profile" do
before(:each) do
#user = User.create(#attr)
#profile = Factory(:user_profile, :user => #user, :created_at => 1.day.ago)
end
it "should have a user profile attribute" do
#user.should respond_to(:user_profile)
end
it "should have the right user profile" do
#user.user_profile.should == #profile
end
it "should destroy associated profile" do
#user.destroy
[#profile].each do |user_profile|
lambda do
UserProfile.find(user_profile)
end.should raise_error(ActiveRecord::RecordNotFound)
end
end
end
My user_profile_spec is setup like so:
describe UserProfile do
before(:each) do
#user = Factory(:user)
#attr = { :state => "GA" }
end
it "should create a new instance with valid attributes" do
#user.user_profiles.create!(#attr)
end
describe "user associations" do
before(:each) do
#user_profile = #user.user_profiles.create(#attr)
end
it "should have a user attribute" do
#user_profile.should respond_to(:user)
end
it "should have the right associated user" do
#user_profile.user_id.should == #user.id
#user_profile.user.should == #user
end
end
end
When I run the tests I get "undefined method `user_profiles' for #". How is my test flawed or is my relationship flawed?
Thanks!
You have a has_one association called user_profile (singular). You do not have an association called user_profiles (plural).

factory_girl wiggin' out over associations (infinite loop, maybe?)

What I have now:
class User < ActiveRecord::Base
has_many :people
end
... and...
class Person < ActiveRecord::Base
belongs_to :user
end
In spec/factories.rb:
Factory.define :user do |u|
u.email "test#test.com"
u.password "testpassword"
u.password_confirmation "testpassword"
u.display_name "neezer"
# u.people { |i| [i.association(:person)] }
end
Factory.define :person do |p|
p.first_name "p_firstname"
p.last_name "p_lastname"
p.gender "male"
p.association :user
end
I want to setup the user factory to create with 1 person association, but if I uncomment that line, when I run my tests, my system hangs for quite some time, before outputting this failure:
1) User can be created from a factory
Failure/Error: Unable to find matching line from backtrace
SystemStackError:
stack level too deep
# /Users/test/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.0.5/lib/active_record/persistence.rb:285
What am I doing wrong here? I would like to have tests that require an association between these two models, such that (1) a User must have at least 1 person, and (2) a Person must belong to a User.
Is this a first-priority issue? I'll admit I'm a bit lost here...
I'm using rspec 2.5.0, factory_girl_rails 1.0.1, and rails 3.0.5.
My specs:
user_spec.rb:
require 'spec_helper'
describe User do
subject { Factory :user }
# ...
context "has associations, " do
it "can have people" do
subject.should respond_to :people
end
it "must have at least 1 person" do
subject.send "people=", nil
subject.should_not be_valid
subject.errors[:people].should_not be_empty
end
end
end
person_spec.rb:
require 'spec_helper'
describe Person do
subject { Factory :person }
# ...
context "has validation, " do
[:gender, :user].each do |attr|
it "must have a #{ attr }" do
subject.send "#{attr}=", nil
subject.should_not be_valid
subject.errors[attr].should_not be_empty
end
end
end
context "has associations, " do
it "can have a User" do
subject.should respond_to :user
end
end
end
Keep that line but remove p.association :user from your person factory.
I've since discovered Shoulda, which provides a nice rspec matchers like these:
subject.should belong_to :user
subject.should have_many :people
Which has solved my issue.