rspec association creation error - ruby-on-rails

I have a model item has_many ratings and a ratings belongs_to item ratings belongs_to user I want to force a user who is creating an item to rate it too. Other users can then rate it later on. item and user have no association in my model.
I am doing the following in my item_spec which is giving me an error no implicit conversion of Symbol into Integer on line #item = Item.new(name: "Item1", below.
class Item < ActiveRecord::Base
has_many :ratings, dependent: :destroy, inverse_of: :item
accepts_nested_attributes_for :ratings, :allow_destroy => true
validates :name , :length => { minimum: 3 }
validates :category , :length => { minimum: 3 }
validates_presence_of :ratings
end
require 'spec_helper'
describe Item do
before do
#item = Item.new(name: "Item1",
url: "www.item1.com",
full_address: "Item1Address",
city: "Item1City",
country: "Item1Country",
category: "Item1Type",
ratings_attributes: {"rating" => "3", "comment" => "Ahh Good"} )
end
Also using FactoryGirl I am doing something like this
factory :item do
before_create do |r|
r.ratings<< FactoryGirl.build(:ratings, item: r )
end
name "Item1"
url "www.Item1.com"
full_address "Item1Address"
city "Item1City"
country "Item1Country"
category "Item1Category"
end
factory :ratings do
rating 3
comment "Its not that bad"
user
end
end
which again is not yeilding the desired result.
can anyone help me solve this problem please.Thanks!

Working Code, now having problem testing some association order, but at least the desired functionality working.
factory :item do
name "Item1"
url "www.Item1.com"
full_address "Item1Address"
city "Item1City"
country "Item1Country"
category "Item1Category"
end
factory :ratings, :class => 'Ratings' do
association :item, factory: :item, strategy: :build
user
rating 3
comment "Its not that bad"
end
factory :item_with_rating, parent: :item do
ratings {[FactoryGirl.create(:ratings)]}
end
Here is the spec file
require 'spec_helper'
describe Item do
before do
#item = FactoryGirl.create(:item_with_rating)
end
subject { #item }
it { should respond_to(:name) }
it { should respond_to(:url) }
it { should respond_to(:full_address)}
it { should respond_to(:city) }
it { should respond_to(:country) }
it { should respond_to(:category) }
it { should respond_to(:ratings) }
it { should_not respond_to(:type) }
it { should_not respond_to(:user_id) }
it { should be_valid }
There is no change in the Model file for item

Related

Factory-bot - How to build association and nested attributes

I am new to Factories and I need help for the association and nested attributes....
How do I set an admin user that creates a product? OK
How do I set category to a product? Ok
How do I attach images to a product? OK
How do I set product's sizes (nested attibutes)
user.rb
has_many :products
product.rb
belongs_to :user
belongs_to :category
has_many :sizes, inverse_of: :product, dependent: :destroy #nested_attributes
size.rb
belongs_to :product
category.rb
has_many :products
factories/users.rb
FactoryBot.define do
factory :user do
first_name { Faker::Name.first_name}
last_name { Faker::Name.last_name }
admin { [false, true].sample }
sequence(:email) { |n| "#{n}#{Faker::Internet.email}" }
birth_date {"20/10/1997"}
password { 'password'}
end
end
factories/categories.rb
FactoryBot.define do
factory :category do
title { Faker::Artist.name }
end
end
factories/sizes.rb
FactoryBot.define do
factory :size do
size_name {["S", "M", "L", "XL"].sample }
quantity { Faker::Number.number(2) }
end
end
factories/products.rb
FactoryBot.define do
factory :product do
title { Faker::Artist.name}
ref { Faker::Number.number(10)}
price { Faker::Number.number(2) }
color { Faker::Color.color_name }
brand { Faker::TvShows::BreakingBad }
description { Faker::Lorem.sentence(3) }
size
category
# how to set an admin ??
end
end
Add associations like this
For product
FactoryBot.define do
factory :product do
user {User.first || association(:user)}
user {User.first || association(:user, admin: true)}
# your admin attribute (role: admin or admin: true) whatever you are using for admin
category {Category.first || association(:category)}
end
end
Read FactoryBot association hope it will help.

FactoryBot one record associated with many attributes

I have User, Assignment and Department models.
My Assignment model has 2 belongs_to associations with the User model as requestor and assignee.
The User and Assignment model also in turn belongs_to a department.
I want to run a validation on my Assignment such that the assignment, requestor and assignee all belong to the same department.
This is my code for the models
# app/models/assignment.rb
class Assignment < ApplicationRecord
belongs_to :requestor, class_name: "User", foreign_key: "requested_by"
belongs_to :assignee, class_name: "User", foreign_key: "assigned_to"
belongs_to :department
end
# app/models/user.rb
class User < ApplicationRecord
has_many :user_departments, class_name: "UserDepartment"
has_many :departments, through: :user_departments
belongs_to :department
end
# app/models/department.rb
class Department < ApplicationRecord
has_many :user_departments, class_name: "UserDepartment"
has_many :users, through: :user_departments
has_many :assignments
has_many :users
end
This is the code for my test
# spec/factories/assignment.rb
FactoryBot.define do
sequence(:title) { |n| "Title #{n}" }
sequence(:description) { |n| "Description #{n}" }
factory :assignment do
title
description
image { Rack::Test::UploadedFile.new(Rails.root.join('spec/support/Floyd.jpeg'), 'image/jpeg') }
release_date { DateTime.now >> 1 }
department { create(:department) }
requestor create(:user, :bm, department: "I want to use the same department as created in earlier line here")
assignee create(:user, :mu, department: "I want to use the same department as created in earlier line here")
end
end
Where should I define the department so I can use the same department across all three associations.
Have you tried self.department? It worked in my code:
# spec/factories/assignment.rb
FactoryBot.define do
sequence(:title) { |n| "Title #{n}" }
sequence(:description) { |n| "Description #{n}" }
factory :assignment do
title
description
image { Rack::Test::UploadedFile.new(Rails.root.join('spec/support/Floyd.jpeg'), 'image/jpeg') }
release_date { DateTime.now >> 1 }
department { create(:department) }
requestor { create(:user, :bm, department: self.department) }
assignee { create(:user, :mu, department: self.department) }
end
end
Hope I got the question right. You want the same department on all the models.
This is a thing you actually do in the spec.
describe Foo::Bar do
before(:each) do
#department = create(:deparment)
#assignment = create(:assignment, department: #department)
#user = create(:user, department: department)
# ....
end
But this always depends on how your overall structure is. When the assignment is the center model and always has a department you could do something like
describe Foo::Bar do
before(:each) do
#assignment = create(:assignment)
#user = create(:user, department: #assignment.department)
# ....
end

Rails SystemStackError: stack level too deep

I am testing my app ( Rails 5) with rspec capybara and factory girl I have the following error...
I am not sure what's happening... I am very new with rspec I hope you could help me :) thank you
Randomized with seed 41137
An error occurred in a `before(:suite)` hook.
Failure/Error: FactoryGirl.lint
SystemStackError:
stack level too deep
You will find my code below:
factories.rb
FactoryGirl.define do
factory :event do
name {Faker::Friends.character}
total_price 50
participant
end
factory :participant do
first_name { Faker::Name.first_name }
salary 900
event
end
end
event.rb
class Event < ApplicationRecord
has_many :participants, inverse_of: :event
validates :participants, presence: true
validates :name, presence: true, length: {minimum: 2}
validates :total_price, presence: true
accepts_nested_attributes_for :participants, reject_if: :all_blank, allow_destroy: true
def total_salary
all_salary = []
participants.each do |participant|
all_salary << participant.salary
end
return #total_salary = all_salary.inject(0,:+)
end
end
event_spec.rb
require 'rails_helper'
describe Event do
it { should have_many(:participants) }
it { should validate_presence_of(:participants) }
it { should validate_presence_of(:name) }
it { should validate_presence_of(:total_price) }
describe "#total_salary" do
it "should return the total salary of the participants" do
partcipant_1 = create(:participant, salary: 2000)
partcipant_2 = create(:participant, salary: 3000)
expect(partcipant_1.salary + partcipant_2.salary).to eq(5000)
end
end
end
edit
In my participant model I had to add optional: true
belongs_to :event, option: true
so fabriciofreitag suggestion works well :)
Let's take a look at your factories:
FactoryGirl.define do
factory :event do
name {Faker::Friends.character}
total_price 50
participant
end
factory :participant do
first_name { Faker::Name.first_name }
salary 900
event
end
end
In this scenario, the creation of event will create a participant, that will create an event, that will create a participant. and so on, in an infinite loop (stack level too deep).
Perhaps you could change it to something like this:
FactoryGirl.define do
factory :event do
name {Faker::Friends.character}
total_price 50
participants { create_list(:participant, 3, event: self) }
end
factory :participant do
first_name { Faker::Name.first_name }
salary 900
end
end

method on model returning empty during rspec tests even though it should have a value

I am doing the following rspec test to test my '#clubs' method
context "#clubs" do
it "returns the users associated Clubs" do
club = create(:club)
user = club.host
expect(user.clubs).to contain(club)
end
end
The method in my User model:
class User < ActiveRecord::Base
has_many :host_clubs, :class_name => 'Club', :inverse_of => :host
has_and_belongs_to_many :volunteer_clubs, :class_name => 'Club', :inverse_of => :volunteers
def clubs
[host_clubs, volunteer_clubs].flatten
end
end
When I run the test and use p club.host, it returns the user as expected, however I cannot see why calling user.clubs => [] returns an empty array. Here is the factory for context.
factory :host, class: User do |f|
f.first_name { Faker::Name.first_name }
f.last_name { Faker::Name.last_name }
f.email { Faker::Internet.email }
f.password { Faker::Internet.password }
f.role { "host" }
f.onboarded_at { Date.today }
after(:create) do |host|
host.confirm_email_address
end
end
factory :club, class: Club do |f|
f.venue_type { "Primary school" }
f.name { Faker::Company.name }
f.address_1 { Faker::Address.street_address }
f.city { Faker::Address.city }
host
end
Can anyone give me a heads up to why it may not be returning the record?
It's worth noting that I am adding this test after the method was created. In the console the method behaves as expected.
(Making my comment as an answer with additional information)
Try user.reload before expecting the results in the test solves this issue.
This is because of club object is created independently from user. This is generally happens in rspec tests.

Using FactoryGirl for resource that belongs to 2 other resources and validates their id's in Rails 4 app

My associations aren't so complex but I've hit a wall making them work with FactoryGirl:
Text: blast_id:integer recipient_id:integer
class Text < ActiveRecord::Base
belongs_to :blast
belongs_to :recipient, class_name: "User"
validates :blast_id, presence: true
validates :recipient_id, presence: true
end
Blast: content:string author_id:integer
class Blast < ActiveRecord::Base
belongs_to :author, class_name: "User"
has_many :texts
validates :author_id, presence: true
end
User: name:string, etc. etc.
class User < ActiveRecord::Base
has_many :blasts, foreign_key: "author_id"
validates :name, presence: true
end
In FactoryGirl I've got:
FactoryGirl.define do
factory :user, aliases: [:author, :recipient] do |u|
sequence(:name) { Faker::Name.first_name }
end
factory :blast do
author
content "Lorem ipsum"
ignore do
texts_count 1
end
after :build do |blast, evaluator|
blast.texts << FactoryGirl.build_list(:text, evaluator.texts_count, blast: nil, recipient: FactoryGirl.create(:user) )
end
end
factory :text do
blast
association :recipient, factory: :user
end
end
Finally, some specs which all fail because Texts is not valid
require 'spec_helper'
describe Text do
User.destroy_all
Blast.destroy_all
Text.destroy_all
let!(:user) { FactoryGirl.create(:user) }
let!(:blast) { FactoryGirl.create(:blast, author: user) }
let(:text) { blast.texts.first }
subject { text }
it { should be_valid }
describe "attributes" do
it { should respond_to(:blast) }
it { should respond_to(:recipient) }
its(:blast) { should == blast }
its(:recipient) { should == recipient }
end
describe "when blast_id is not present" do
before { text.blast_id = nil }
it { should_not be_valid }
end
describe "when recipient_id is not present" do
before { text.recipient_id = nil }
it { should_not be_valid }
end
end
All the specs fail on FactoryGirl blast creation with:
1) Text
Failure/Error: let!(:blast) { FactoryGirl.create(:blast, author: user) }
ActiveRecord::RecordInvalid:
Validation failed: Texts is invalid
# ./spec/models/text_spec.rb:8:in `block (2 levels) in <top (required)>'
I've tried various iterations of the association code in the FactoryGirl docs and other question answers like this one but my situation is different enough that I can't get it to work.
If you've made it this far, thank you! Super grateful for any leads.
Your factory for "blast" should look like
factory :blast do
author
content "Lorem ipsum"
ignore do
texts_count 1
end
after :build do |blast, evaluator|
blast.texts << FactoryGirl.build_list(:text, evaluator.texts_count, blast: blast, recipient: FactoryGirl.create(:user) )
end
end
In other words, you immediately create the correct "parent" by connecting the newly created blast to the newly created tekst
To further dry your code, have a look at https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#configure-your-test-suite, describing how to get rid of using "FactoryGirl." over and over again by setting
config.include FactoryGirl::Syntax::Methods
once in your settings

Resources