Still a bit new to rspec and can't get the following test to pass (problem area the 'it "should have the right treatings in the right order" do' block):
user_spec.rb
describe User do
before do
#user = User.new(name: "Example User", email: "user#example.com",
password: "foobar", password_confirmation: "foobar")
end
describe "treating associations" do
before { #user.save }
let!(:older_treating) do
FactoryGirl.create(:treating, user: #user, created_at: 1.day.ago)
end
let!(:newer_treating) do
FactoryGirl.create(:treating, user: #user, created_at: 1.hour.ago)
end
it "should have the right treatings in the right order" do
#user.sent_treatings.should == [newer_treating, older_treating]
#user.received_treatings.should == [newer_treating, older_treating]
end
end
end
Based on my User and Treating models below, I know I need to have 'requestor' and 'requestee' embedded somewhere in the test, and I have tried different variations, but they all continue to fail. Here are the models:
user.rb
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
has_many :sent_treatings, :foreign_key => "requestor_id", :class_name => "Treating"
has_many :received_treatings, :foreign_key => "requestee_id", :class_name => "Treating"
end
treating.rb
class Treating < ActiveRecord::Base
attr_accessible :intro, :proposed_date, :proposed_location
validates :requestor_id, presence: true
validates :requestee_id, presence: true
belongs_to :requestor, class_name: "User"
belongs_to :requestee, class_name: "User"
default_scope order: 'treatings.created_at DESC'
end
Here is my factories.rb file:
factories.rb
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
factory :admin do
admin true
end
end
factory :treating do
intro "Lorem ipsum"
user
end
end
Looking for an explanation of logic behind the appropriate code to fill in the ' it "should have the right treatings in the right order" do' block of the user_spec test. Thanks!
EDIT: sorry, forgot error message, here it is:
Failures:
1) User treating associations should have the right treatings in the right order
Failure/Error: FactoryGirl.create(:treating, user: #user, created_at: 1.day.ago)
NoMethodError:
undefined method user=' for #<Treating:0x0000010385ec70>
# ./spec/models/user_spec.rb:143:inblock (3 levels) in '
You are trying to override a field which doesn't exist.
You don't have user but a requestor or requestee.
Try for example
FactoryGirl.create(:treating, requestor: #user, created_at: 1.hour.ago)
Related
I'm trying to test the 'destroy' action for my nested comments controller.
In my filmweb app I have scope and validations which prevents users from deleting a comment which is not the author. In web version everything works well but I don't know how to test this case.
Here is my comments_controller
def destroy
#comment = #movie.comments.find(params[:id])
if #comment.destroy
flash[:notice] = 'Comment successfully deleted'
else
flash[:alert] = 'You are not the author of this comment'
end
redirect_to #movie
end
Comment model
class Comment < ApplicationRecord
belongs_to :user
belongs_to :movie
validates :body, presence: true
validates :user, :movie, presence: true
validates :user, uniqueness: { scope: :movie }
scope :persisted, -> { where.not(id: nil) }
end
User model has_many :comments, dependent: :destroy Movie model has_many :comments, dependent: :destroy .
I'm using devise and FactoryBot, specs are here:
describe "DELETE #destroy" do
let(:user) { FactoryBot.create(:user) }
let(:movie) { FactoryBot.create(:movie) }
let(:other_user) { FactoryBot.create(:user, user_id: 100)}
it "doesn't delete comment" do
sign_in(other_user)
comment = FactoryBot.create(:comment, movie: movie, user: user)
expect do
delete :destroy, params: { id: comment.id, movie_id: movie.id }
end.to_not change(Comment, :count)
expect(flash[:alert]).to eq "You are not the author of this comment"
end
end
I've got an error undefined method `user_id=' for #<User:0x00007fb049644d20> and no idea what is the good way to do so.
===EDIT===
Here is my FactoryBot
FactoryBot.define do
factory :user do
email { Faker::Internet.email }
password "password"
confirmed_at 1.day.ago
end
factory :unconfirmed_user do
email { Faker::Internet.email }
password "password"
end
end
The problem is that the the users table does not have a user_id column which you are trying to use in the other_user instance, the column name is simply id:
let(:other_user) { FactoryBot.create :user, id: 100 }
You can leave out the id entirely, it will get a different id automatically:
let(:other_user) { FactoryBot.create :user }
I cannot get Factory Girl to produce a User object when accepts_nested_attributes_for is enabled.
Given the models:
class Account < ApplicationRecord
belongs_to :meta, polymorphic: true, dependent: :destroy
end
class User < ApplicationRecord
has_one :account, as: :meta
validates :fname, presence: true
validates :lname, presence: true
validates_presence_of :account
#accepts_nested_attributes_for :account
end
And, the factories:
FactoryGirl.define do
factory :account do
sequence(:email) { |n| "account#{n}#mack.com" }
password "abcdef123"
password_confirmation "abcdef123"
confirmed_at Date.today
end
end
FactoryGirl.define do
factory :user do
sequence(:fname) { |n| "first#{n}" }
sequence(:lname) { |n| "last#{n}" }
after(:build) do |user|
user.build_account attributes_for(:account)
end
end
end
The following spec:
describe User, :type => :model do
it "has a valid factory" do
user = build(:user)
expect(user).to be_valid
end
end
Fails if I uncomment the accepts_nested_attributes_for in the User model. I would like to use the nested attributes for working with User objects, but I cannot figure out how to get FactorGirl to build a User with nested attributes enabled.
I get the following error:
1) User has a valid factory
Failure/Error: expect(user).to be_valid
expected #<User id: nil, fname: "first1", lname: "last1", created_at: nil, updated_at: nil> \
to be valid, but got errors: Account meta must exist
I am using Rails version 5.0.0beta1 and Factory Girl 4.6.0.
I've been battling this all day -- thanks for your help.
Edit: I see the same behavior using the rails console, so it would seem like the issue is independent of Factory Girl.
I think I know what the problem is here, but I can't seem to figure out how to fix it.
here are my models
User
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation
has_many :student_groups
...
end
StudentGroup
class StudentGroup < ActiveRecord::Base
attr_accessible :name
belongs_to :user
has_many :subjects
has_many :students
end
Subject
class Subject < ActiveRecord::Base
attr_accessible :end_date, :name
belongs_to :student_group
belongs_to :student
end
Student
class Student < ActiveRecord::Base
attr_accessible :gender, :name
belongs_to :student_group
has_many :subjects
end
in my Student_Spec.rb I have the following test EDITED:
...
before(:each) do
#user = Factory(:user)
#student_group_attr = { name: "4a"}
#student_group = #user.student_groups.create(#student_group_attr)
#date = Date.today+180
#subject_attr = { name: "English", end_date: #date}
end
...
describe "Student associations" do
before(:each) do
#subject = #student_group.subjects.create!(#subject_attr)
#student_attr = { name: "Example Student", gender: "Female" }
#student = #student_group.students.create(#student_attr)
end
it "should have the right associated student" do
#subject.student_id.should == #student.id
#subject.student.should == #student
end
end
I have the same test in other specs and it works fine - I checked it out in the console and got this:
2.0.0-p0 :015 > #subject
=> #<Subject id: 1, name: "English", student_group_id: 1, student_id: nil, end_date: "2013-11-18", created_at: "2013-05-22 15:08:44", updated_at: "2013-05-22 15:08:44">
So for whatever reason, the student_id isn't getting linked to the subject...what am I doing wrong here? Thanks!
Reload #subject, maybe its not loaded from the db and therefore its empty
Figured it out.
Changed models to the following:
student_groups.rb
class StudentGroup < ActiveRecord::Base
attr_accessible :name
belongs_to :user
has_many :students
end
students.rb
class Student < ActiveRecord::Base
attr_accessible :gender, :name
belongs_to :student_group
has_many :subjects
end
subject.rb
class Subject < ActiveRecord::Base
attr_accessible :end_date, :name
belongs_to :student
end
And model specs to the following:
student_group_spec.rb
require 'spec_helper'
describe StudentGroup do
before(:each) do
association_attr
end
it "should create a new instance with valid attributes" do
#user.student_groups.create!(#attr).should be_valid
end
describe "User associations" do
it "should have a user attribute" do
#student_group.should respond_to(:user)
end
it "should have the right associated user" do
#student_group.user_id.should == #user.id
#student_group.user.should == #user
end
end
describe "Student associations" do
it "should have a student attritube" do
#student_group.should respond_to(:students)
end
end
end
student_spec.rb
require 'spec_helper'
describe Student do
before(:each) do
association_attr
end
it "should create a new instance with valid attributes" do
#student_group.students.create!(#attr).should be_valid
end
describe "Student_Group associations" do
it "should have a student_group attribute" do
#student.should respond_to(:student_group)
end
it "should have the right associated student_group" do
#student.student_group_id.should == #student_group.id
#student.student_group.should == #student_group
end
end
describe "Subject associations" do
it "should have a subject attribute" do
#student.should respond_to(:subjects)
end
end
end
subject_spec.rb
require 'spec_helper'
describe Subject do
before(:each) do
association_attr
end
it "should create a new instance with valid attributes" do
#student.subjects.create!(#subject_attr).should be_valid
end
describe "Student associations" do
it "should have a student attribute" do
#subject.should respond_to(:student)
end
it "should have the right associated student" do
#subject.student_id.should == #student.id
#subject.student.should == #student
end
end
end
And finally changed spec_helper.rb as follows:
def association_attr
# User attritbutes
#user = Factory(:user)
# Student_group
#student_group = #user.student_groups.create(#student_group_attr)
# Student_group attributes
#student_group_attr = { name: "4a"}
# Student
#student = #student_group.students.create(#student_attr)
# Student attributes
#student_attr = { name: "Example Student", gender: "Transgender" }
# Subject
#subject = #student.subjects.create!(#subject_attr)
# Subject attributes
#subject_attr = { name: "English", end_date: #date}
#date = Date.today+180
end
Thanks to Frederick Cheung and Billy Chan for the comments.
I have implemented cancan and would like to test abilities as recommended on the cancan wiki. I trying to replicate "user can only destroy projects which he owns."
spec/models/ability_spec.rb:
require "cancan/matchers"
require 'spec_helper'
describe Ability do
context "user is investigator" do
it "user can only destroy projects which he owns" do
user = FactoryGirl.create(:user)
ability = Ability.new(user)
ability.should be_able_to(:destroy, Project.new(:user => user))
end
end
end
However I get:
ActiveModel::MassAssignmentSecurity::Error:
Can't mass-assign protected attributes: user
Models:
class User < ActiveRecord::Base
has_many :projects, dependent: :destroy
devise :database_authenticatable, etc...
attr_accessible :email, :password, :password_confirmation, :remember_me, :locale
validates :role, :presence => true
end
class Project < ActiveRecord::Base
belongs_to :user
end
Factory:
FactoryGirl.define do
factory :user do |f|
f.email { Faker::Internet.email }
f.password "secret"
f.role 1
end
end
I understand why this error arrises, and have tried various ways round it, but don't have a good enough understanding of factories to crack it. Can you help?
So the problem was related to not using Factory Girl when creating the project. It should have been:
describe Ability do
context "user is investigator" do
it "user can only destroy projects which he owns" do
user = FactoryGirl.create(:user)
ability = Ability.new(user)
ability.should be_able_to(:destroy, FactoryGirl.create(:project, :user => user))
end
end
end
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.