This is my factory girl code, and every time I try to generate a review, it's telling me that "Email has already been taken", i've reset my databases, set the transition in spec_helper to true, but still haven't solved the problem. I'm new to this, am I using the association wrong? Thanks!
Factory.define :user do |user|
user.name "Testing User"
user.email "test#example.com"
user.password "foobar"
user.password_confirmation "foobar"
end
Factory.define :course do |course|
course.title "course"
course.link "www.umn.edu"
course.sections 21
course.description "test course description"
course.association :user
end
Factory.define :review do |review|
review.title "Test Review"
review.content "Test review content"
review.association :user
review.association :course
end
I know this is a pretty old question, but the accepted answer is out of date, so I figured I should post the new way of doing this.
FactoryGirl.define do
sequence :email do |n|
"email#{n}#factory.com"
end
factory :user do
email
password "foobar"
password_confirmation "foobar"
end
end
Source: Documentation
It's quite a bit simpler, which is nice.
You need to use a sequence to prevent the creation of user objects with the same email, since you must have a validation for the uniqueness of emails in your User model.
Factory.sequence :email do |n|
“test#{n}#example.com”
end
Factory.define :user do |user|
user.name "Testing User"
user.email { Factory.next(:email) }
user.password "foobar"
user.password_confirmation "foobar"
end
You can read more in the Factory Girl documentation.
In addition to the above answers you could add gem 'faker' to your Gemfile and it will provide unique emails.
FactoryGirl.define do
factory :admin do
association :band
email { Faker::Internet.email }
password "asdfasdf"
password_confirmation "asdfasdf"
end
end
sequence gives really unique email and Faker gives random password.
FactoryGirl.define do
sequence :email do |n|
"user#{n}#test.com"
end
factory :user do
email
password { Faker::Internet.password(min_length: 8, max_length:20) }
password_confirmation { "#{password}" }
end
end
For some reason the password_confirmation field wasn't working for me. What worked was this:
FactoryBot.define do
sequence :email do |n|
"user#{n}#test.com"
end
factory :user do
email
password { Faker::Internet.password(min_length: 8, max_length:20) }
confirmed_at { Time.current } # <---- This worked for me
end
end
Note that if you're not using Faker, you can have something as simple as `password { "password" } instead of that line.
Related
I'm trying to instanciate with FactoryGirl multiple object (guests who have unique email)
guests = create_list(:guest, 3)
But I get error :
Failure/Error: guests = create_list(:guest, 3)
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
Here my factory :
FactoryGirl.define do
factory :guest do
email Faker::Internet.unique.email
firstname 'John'
lastname 'Doe'
password 'test'
password_confirmation 'test'
factory :guest_with_bookings do
email "#{SecureRandom.hex}#test.com"
transient do
bookings_count 2
end
after(:create) do |guest, evaluator|
create_list(:booking, evaluator.bookings_count, guests: [guest])
end
end
end
end
Even with Faker::Internet.unique.email, it's don't working when I try to create more than 1 guest
Use sequence in your factory
FactoryGirl.define do
factory :guest do
sequence(:email) { |n| "name_#{n}#example.com" }
Or in combination with Faker
FactoryGirl.define do
factory :guest do
sequence(:email) { |n| Faker::Internet.unique.email("Nancy_#{n}") }
I have a question in Rails 4.
On my factories.rb i have something like:
factory :user do
sequence(:name) { |n| "User #{n}" }
sequence(:email) { |n| "user_#{n}#example.org" }
password 'foobar'
password_confirmation 'foobar'
end
The problem, i don't know to add a relation after created user.
When i create a user, and he is a moderator i assign to user the role like that:
u.add_role_id!(11)
I have different table for relationships, with user_id and role_id and on user model i have the method.
def add_role_id!(role)
role_user_relationship.create!(role_id: Role.find(role).id)
end
How i do that on factories.rb?
Now what i now to do:
u = FactoryGirl.create(:moderator)
u.add_role_id!(11)
I want to assign by default on factories.rb
How I do that?!
Thanks everybody!
Manu
Solution:
I have to add these lines:
after(:create) do |u|
u.add_roles_ids!([10,20,30])
end
With the entire code:
factory :user do
sequence(:name) { |n| "User #{n}" }
sequence(:email) { |n| "user_#{n}#mudev.org" }
password 'foobar'
password_confirmation 'foobar'
after(:create) do |u|
u.add_roles_ids!([10,20,30])
end
end
Thanks to Peter Alfvin
You can use FactoryGirl's after callback mechanism described at https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#callbacks to get the comparable behavior to what you're doing now by including the following within your factory definition:
after(:create) {|u| u.add_role_id!(11)
Depending on your validation, you can alternatively do this after(:build) or before(:create).
So I have been racking my brain at this and maybe some of you might have a better idea on how to do proper unit test for this User model. My basic unit test looks like this.
test "should not save without name" do
user = User.new
user.email = "test#test.com"
user.password = "letmein"
assert !user.save
end
This test passes with this model.
class User < ActiveRecord::Base
include Clearance::User
validates :name, presence: true
has_and_belongs_to_many :contests
end
Is there a better way to do this in Clearance? It is nice the gem lets you create users like this on the fly by arbitrarily assigning email and password but I'm thinking maybe I shouldn't have to do this.
user = User.new(:email => "test#test.com", :password => "letmein")
and then,
assert !user.valid?
or
user.should_not be_valid
or
expect { user.save }.to change(User, :count).by(0)
I have the following test:
test "should get create" do
sign_in(FactoryGirl.create(:user))
assert_difference('Inquery.count') do
post :create, FactoryGirl.build(:inquery)
end
assert_not_nil assigns(:inquery)
assert_response :redirect
end
and I keep getting:
2) Error:
test_should_get_create(InqueriesControllerTest):
ActiveRecord::RecordInvalid: Validation failed: Email has already been taken, License number has already been taken
What I don't understand is why I get this error in this particular test, when I have a very similar test:
test "should get create" do
sign_in(FactoryGirl.create(:user, admin: true))
assert_difference('Event.count') do
post :create, FactoryGirl.build(:event)
end
assert_not_nil assigns(:event)
assert_response :success
end
and this does just fine. The obvious difference is the admin: true line, but that has no effect as I suspected.
Added:
User_factory.rb
factory :user do
first_name "John"
last_name "Doe"
email "example#example.com"
password "foobar"
password_confirmation "foobar"
license_number '12345'
state 'AZ'
specialty 'Neurosurgery'
end
Your User is failing validations because your factory is setting up a new user for your test, but your database isn't being cleared in between. Change your factory to look like this, so that email and license_number are unique each time you create a User:
factory :user do
first_name "John"
last_name "Doe"
sequence(:email) { |n| "example#{n}#example.com" }
password "foobar"
password_confirmation "foobar"
sequence(:license_number) { |n| "12345#{n}" }
state 'AZ'
specialty 'Neurosurgery'
end
This is my current testing setup:
# spec/factories.rb
require 'factory_girl'
FactoryGirl.define do
# Roles
factory :user_role, :class => Role do
name 'User'
end
# Users
factory :user, :class => User do
sequence(:email) {|n| "email#{n}#example.com" }
password 'password'
password_confirmation 'password'
name 'Yuri Userington'
roles { |a| [a.association(:user_role)] }
end
# Instruments
factory :instrument, :class => Instrument do
title "Doobie Doo Instrument Title"
is_valid true
association :user, :factory => :user
end
# Sequences
sequence :email do
"email#{n}#factory.com"
end
end
# spec/controllers/instruments_controller_spec.rb
require 'spec_helper'
describe InstrumentsController do
before (:each) do
#instrument = FactoryGirl.create(:instrument)
#attr = FactoryGirl.attributes_for(:instrument)
#user = FactoryGirl.create(:user)
end
describe "GET index" do
it "assigns all instruments as #instruments" do
instrument = Instrument.new(#attr)
instrument.user = #user
instrument.save!
get :index
assigns(:instruments).should eq([instrument])
end
end
end
The result is that when i run my tests, i get the following errors in my output:
Failures:
1) InstrumentsController GET index assigns all instruments as #instruments
Failure/Error: #instrument = FactoryGirl.create(:instrument)
ActiveRecord::RecordNotFound:
Couldn't find Role with id=2
# ./app/models/user.rb:21:in `assign_role_after_sign_up'
# ./spec/controllers/instruments_controller_spec.rb:24:in `block (2 levels) in <top (required)>'
Based on that it seems like the roles association call in my :user factory is NOT being called -- what am i doing wrong here? Am i using this in a completely wrong way?
thank you!!
There is much to say here. Compare your code with the following to see how many lines or words were removed.
FactoryGirl.define do
# Sequences
sequence :email do |n|
"email#{n}#factory.com"
end
# Roles
factory :user_role, :class => Role do
name 'User'
end
# Users
factory :user do
email
password 'password'
password_confirmation 'password'
name 'Yuri Userington'
roles { |user| [Factory(:user_role)] } #many to many
end
# Instruments
factory :instrument, :class => Instrument do
title "Doobie Doo Instrument Title"
is_valid true
association :user #one-to-one or one-to-many
end
end
And in your tests:
describe InstrumentsController do
before (:each) do
#user = Factory(:user)
end
describe "GET index" do
it "assigns all instruments as #instruments" do
instrument = Factory(:instrument, :user => #user)
get :index
assigns(:instruments).should eq([instrument])
end
end
end
Moreover:
I personally prefer testing controller with mocks and stubs
I use let instead of instance variables and before_filter
I had a similar issues and I used a callback to assign roles like this:
Factory.define :user_with_admin_role, :parent => :user do |user|
user.after_create {|instance| instance.roles << Factory(:admin_role) }
end
So I think you should be able to do something akin to that:
# Users
factory :user, :class => User do
sequence(:email) {|n| "email#{n}#example.com" }
password 'password'
password_confirmation 'password'
name 'Yuri Userington'
after_create {|user| user.roles << Factory(:user_role) }
end
That is completely untested, so you may need to tweak things around.