I have a User that has_many posts in Rails 4.1.6. Following the Getting Started page for Factory Girl, I have created these factories:
factory :post do
skip_create
title 'foo bar'
user
end
factory :user do
skip_create
id 1
username 'alice'
factory :user_with_posts do
skip_create
transient do
posts_count 5
end
after(:build) do |user, evaluator|
build_list(:post, evaluator.posts_count, user: user)
end
end
end
But calling build(:user_with_posts) returns a User with an empty posts array. Calling build_list(:post, 5, user: user) (with a pre-built User) works.
What am I missing?
Also, is there a way to set a global skip_create so I don't have to set it on each factory?
I had a similar problem, and all according to all the docs I was reading, it should have been working. Here is what finally worked (adapted for your code):
change
build_list(:post, evaluator.posts_count, user: user)
to
user.posts = build_list(:post, evaluator.posts_count, user: user)
Let me know if that doesn't work, but that's what solved it for me.
Related
I have a user factory that be default creates an association for user_document
FactoryGirl.define do
factory :user do |u|
sequence(:first_name) {|n| "firstname-#{n}" }
after(:create) do |user|
create(:user_document, document_type: :address_proof, user: user)
end
end
end
I'd like to define a new factory for which the association user_document is null. How do I do this ?
[UPDATE]
When I do this
factory :user_with_no_doc_buyer do
user_document nil
end
I get an error saying :
NoMethodError: undefined method `user_document=' for #<User:0x007f97329c08f8>
and When I do
user_documents nil I get
NoMethodError: undefined method `each' for nil:NilClass
thanks
I'd create two traits.
FactoryGirl.define do
factory :user do
sequence(:first_name) {|n| "firstname-#{n}" }
trait :with_document do
after(:create) do |user|
create(:user_document, document_type: :address_proof, user: user)
end
end
trait :without_document do
user_documents []
end
end
end
Then you just call whichever factory you need.
FactoryGirl.create(:user, :with_document) for example
Edit: Have seen you want the with document to be the default. That's easy enough. You can just use the code you have and take my suggestion of a trait without document which you can call when you need it.
Use traits
FactoryGirl.define do
factory :user do |u|
sequence(:first_name) {|n| "firstname-#{n}" }
trait :with_user_document
after(:create) do |user|
create(:user_document, document_type: :address_proof, user: user)
end
end
end
end
To create user with document
FactoryGirl.create(:user, :with_user_document)
To create user with null document
FactoryGirl.create(:user)
I've just started using FactoryGirl for my tests, and I've run into some issues.
I have user, qualification and user_qualification models. For qualifications, I have two inherited factories, namely qualification_ba and qualification_phd. Now, I'm trying to generate a qualification that includes either qualification_ba or qualification_phd factories by running:
create(:user_qualification_ba_bad_marks).
This returns:
NoMethodError: undefined method 'qualification_ba='.
However, when running:
create(:qualification_ba)
it successfully creates the object as expected. Is there perhaps a limit on how deep you can nest factories?
factory :user do
to_create {|instance| instance.save(validate: false) }
full_name Faker::Name.name
email Faker::Internet.email
password Faker::Internet.password(8)
factory :user_ba_candidate do
before(:create) do |user|
create_list(:user_qualification_ba_bad_marks, 1, user: user)
end
end
factory :user_phd_candidate do
before(:create) do |user|
create_list(:user_qualification_phd_good_marks, 1, user: user )
end
end
end
factory :qualification do
user_selectable true
factory :qualification_ba do
name "Bachelors"
qualification_level 2
end
factory :qualification_phd do
name "Masters"
qualification_level 5
end
end
factory :user_qualification do
to_create {|instance| instance.save(validate: false) }
factory :user_qualification_ba_bad_marks do
qualification_ba
aggregate (30..50).to_a.sample
end
factory :user_qualification_phd_good_marks do
qualification_phd
aggregate (70..90).to_a.sample
end
user
end
I'm trying to setup my factory girl that when I passed in create(:user, :admin), it will create a user and add a record in the Role model/table. My association is that, User has_one Role, Role belongs_to User
This is the setup of my factory girl
FactoryGirl.define do
factory :user do
name "Test User"
email "test_user#serviceseeking.com.au"
contact_phone "0412345678"
password "123123"
password_confirmation "123123"
skip_email_validation true
trait :as_admin do
factory(:role) { name "Untouchable" }
end
end
end
But for some reason, it doesn't create the role.
What errors are you getting?
I think you should be getting an error saying that there is no trait called :admin. If you want to create admin users with a call to create(:user, :admin) your trait must be named :admin.
Secondly I also think that what you want to do inside the :admin trait is this:
trait :admin do
role name: "Untouchable"
end
If you have your association set up and a factory for Role called :role this should create a Role record with the name "Untouchable" and associate it with your user.
I hope this helps!
My User model has the following action:
def release(idea)
if idea.status == "claimed"
idea.status = "available"
self.ideas.delete(idea)
end
end
Each user has_many ideas, and this is the way to release an idea and say "I don't want to be responsible for this idea anymore."
However, the current implementation lets one user release an idea owned by another user. I could easily solve this in the function itself by checking for idea.user_id but I'm trying to learn how to use CanCan and rolify... which is where the problem starts.
ability.rb says:
if user.has_role? :user
can :release, Idea, user_id: user.id
end
This fails in rspec:
Failures:
1) User manipulates ideas: can't change an idea he doesn't own
Failure/Error: let(:james) {create(:user)}
NoMethodError:
undefined method `find_or_create_by' for #<Rolify::Adapter::ResourceAdapter:0xabc7d98>
tl;dr: Should I be specifying abilities for User or for Idea? If User, how should I word the condition?
Thank you!
Edit: User factory:
FactoryGirl.define do
factory :user do
name Faker::Name.name
email Faker::Internet.email
provider "MyString"
uid {"user_#{rand(1000).to_s}" }
trait :admin do
after(:create) {|user| user.add_role(:admin)}
end
trait :guest do
after(:create) {|user| user.add_role(:guest)}
end
trait :authorized_user do
after(:create) do |user|
user.add_role(:user)
user.remove_role(:guest)
end
end
end
end
I'm testing a controller in my app which should render one view for users who've given over their info and requested access ("signed in guests") and another view for the rest of the world (anonymous users). I'm using OmniAuth and Rolify.
Test goes like this:
context 'signed in guests' do
before do
guest = create(:user,:guest)
OmniAuth.config.mock_auth[:google] = {
uid: guest.uid
}
session[:user_id] = guest.id
end
it "shows the Please Wait for Confirmation view" do
puts "Rspec says Current User: #{#current_user.inspect}"
get :index
response.should render_template :pending_authorization
end
end
User factory looks like this:
FactoryGirl.define do
factory :user do
name "MyString"
email "MyString"
provider "MyString"
uid "MyString"
trait :admin do
after(:create) {|user| user.add_role(:admin)}
end
trait :guest do
after(:create) {|user| user.add_role(:guest)}
end
trait :authorized_user do
after(:create) {|user| user.add_role(:user)}
end
end
end
However, when I run this, my puts actually gives me this:
Rspec says Current User: nil
So... why is the current user nil even though I create it with the omniauth mock?
Edit: current_user comes from my application helper, if that helps any.
Thanks in advance!