Attribute not accessible via Rspec - ruby-on-rails

Models:
class User < ActiveRecord:Base
has_many :roles
has_many :networks, :through => :roles
end
class Network < ActiveRecord:Base
has_many :roles
has_many :network, :through => :roles
end
class Role < ActiveRecord:Base
attr_accesible :user_id, :network_id, :position
belongs_to :user
belongs_to :network
end
The default for role is "member"
In the console I can type:
> #role = Role.find(1)
> #role.position
=> "member"
But in my Rspec tests, I use FactoryGirl to create a user, network, and role. And I have the test #role.should respond_to(:position) I have also tried just assigning it #role.position = "admin". And no matter what, I get an error like:
Failure/Error: #role.should respond_to(:position)
expected [#<Role id:1, user_id: 1, position: "member", created_at...updated_at...>] to respond to :position
Am I missing something very basic?
EDIT:
factories.rb
FactoryGirl.define do
factory :user do
name "Example User"
sequence(:email) {|n| "email#{n}#program.com"}
end
factory :network do
sequence(:name) {|n| "Example Network #{n}"}
location "Anywhere, USA"
description "Lorem Ipsum"
end
factory :role do
association :user
association :network
position "member"
end
end
network_controller_spec
...
before(:each) do
#user = test_sign_in(FactoryGirl.create(:user)
#network = FactoryGirl.create(:network)
#role = FactoryGirl.create(:role, :user_id => #user.id, :network_id = #network.id)
#I have also tried without using (_id) I have tried not setting the position in the factories as well.
end
it "should respond to position" do
get :show, :id => #network
# This may not be the best or even correct way to find this. But there should only be one, and this method works in the console.
#role = Role.where(:user_id => #user.id, :network_id => #network.id)
#role.should respond_to(:position)
end

Jesse is correct in his comment, hopefully he will come back and write it as an answer, in the meantime, the code should be:
#role = Role.where(:user_id => #user.id, :network_id => #network.id).first
or
#role = Role.find_by_user_id_and_network_id(#user.id, #network.id)
As an aside, it seems a little odd to be testing the role class in the network controller spec (unless this is just an exploratory test to work out why things aren't working as expected).

Related

Factory Girl rspec issue: has_many through factory

I am having an issue regarding Factory Girl in Rails. I currently have pundit setup am trying to test my user policies yet the factory does not seem to work when in rspec.
Inside the rails console, I can load up the console and type:
user=FactoryGirl.create(:admin_user)
r=user.roles
This works correctly creates a user and the correct associations between a user and a role. However, when the factory is used in rspec- A user is created but not the associated assignment. (I discovered this by using 'pp' inside the specific tests.)
I do not need to create a role, since the roles are set so I am looking them up.
Any ideas?
Models
class User < ApplicationRecord
has_many :assignments, dependent: :destroy
has_many :roles, through: :assignments, dependent: :destroy
def has_role?(roles)
roles.each do |role|
if self.roles.include? role
return true
end
end
false
end
class Role < ApplicationRecord
# Associations
has_many :assignments
has_many :users, through: :assignments
class Assignment < ApplicationRecord
# Associations
belongs_to :user
belongs_to :role
Factories
FactoryGirl.define do
factory :user do
first_name {Faker::Name.first_name}
last_name {Faker::Name.last_name}
email {Faker::Internet.email}
password {Faker::Internet.password(8)}
factory :admin_user do
after(:create) do |user|
Assignment.create(user: user , role: Role.find_by(label:'System Admin') )
end
end
end
end
Tests
User Policy Test
describe UserPolicy do
subject { UserPolicy }
let (:current_user) { FactoryGirl.build_stubbed :user}
let (:other_user) { FactoryGirl.build_stubbed :user }
let (:admin) { FactoryGirl.build_stubbed :admin_user}
permissions :index? do
it "denies access if not an admin" do
expect(UserPolicy).not_to permit(current_user)
end
it "allows access for an admin" do
expect(UserPolicy).to permit(admin)
end
end
end
Other Test With same Issue
feature 'User index page', :devise do
after(:each) do
Warden.test_reset!
end
scenario 'user sees own email address' do
user = FactoryGirl.create(:admin_user)
expect(user.has_role?(Role.where(label: 'System Admin'))).to eq true
login_as(user, scope: :user)
visit users_path
expect(page).to have_content user.email
end
end
This test fails since the user has no role assigned.
Controller
class AssignmentsController < ApplicationController
def create
#assignment = Assignment.new(assignment_params)
if #assignment.save
redirect_to users_path(), :notice => "Role Added"
else
flash[:alert]="Unable to Add Role"
end
end

Rails 3 - Factory girl and sequence for belongs_to table

I have 2 models - User and Teacher. Teacher belongs_to User, User has Teacher.
So, i use Factory girl gem:
Factory.define :user do |user|
user.user_login "Another User"
user.user_role "admin"
user.password "foobar"
end
Factory.sequence :user_login do |n|
"person-#{n}"
end
Factory.define :teacher do |teacher|
...
teacher.user
end
I met problem and i don't understand how to solve that. When i create user via factory i can easily write:
#user = Factory( :user, :user_login => Factory.next(:user_login) )
And this creates user with inique login.
How can i do same thing for teacher? I tried that:
#teacher = Factory( :teacher, :user_login => Factory.next(:user_login) )
And it doesn't work.
You don't have to specify sequences separately and then pass them to another factory - you can use them inside factories like this:
Factory.define :user do |user|
# ...
user.sequence(:user_login) { |n| "person=#{n}" }
end
or shorter
Factory.define :user do
# ...
sequence(:user_login) { |n| "person=#{n}" }
end
Then, to association a user with teacher:
Factory.define :teacher do
association :user
end
Then you can just call
#teacher = Factory(:teacher)
which will automatically create the associated user with the next user_login in the sequence.
I solved that.
#teacher = Factory( :teacher,
:user => Factory(:user, :user_login => Factory.next(:user_login)) )

How do I create a factory for models that have a has_one/belongs_to relationship with validations that are usually overcome by nested attributes?

I have an Account model that has_one User model, and a User model that belongs_to Account model. I think that the basic code required for demonstration is:
class Account < ActiveRecord::Base
has_one :user
validates_presence_of :user
accepts_nested_attributes_for :user
end
class User < ActiveRecord::Base
belongs_to :account
# validates_presence_of :account # this is not actually present,
# but is implied by a not null requirement
# in the database, so it only takes effect on
# save or update, instead of on #valid?
end
When I define associations in each factory:
Factory.define :user do |f|
f.association :account
end
Factory.define :account do |f|
f.association :user
end
I get a stack overflow, as each is creating an account/user recursively.
The way I've been able to solve this is to emulate nested attribute forms in my tests:
before :each do
account_attributes = Factory.attributes_for :account
account_attributes[:user_attributes] = Factory.attributes_for :user
#account = Account.new(account_attributes)
end
However, I'd like to keep this logic in the factory, as it can get out of hand once I start adding other modules:
before :each do
account_attributes = Factory.attributes_for :account
account_attributes[:user_attributes] = Factory.attributes_for :user
account_attributes[:user_attributes][:profile_attributes] = Factory.attributes_for :profile
account_attributes[:payment_profile_attributes] = Factory.attributes_for :payment_profile
account_attributes[:subscription_attributes] = Factory.attributes_for :subscription
#account = Account.new(account_attributes)
end
Please help!
I was able to solve this problem by using factory_girl's after_build callback.
Factory.define :account do |f|
f.after_build do |account|
account.user ||= Factory.build(:user, :account => account)
account.payment_profile ||= Factory.build(:payment_profile, :account => account)
account.subscription ||= Factory.build(:subscription, :account => account)
end
end
Factory.define :user do |f|
f.after_build do |user|
user.account ||= Factory.build(:account, :user => user)
user.profile ||= Factory.build(:profile, :user => user)
end
end
This will create the associated classes before the owning class is saved, so validations pass.
Have a look at the factory_girl documentation. The way you're building those accounts seems like you're not really taking advantage of factory_girl.
I've always taken care of associations by creating the objects that I need before testing. I'm going to take a stab at this based on the models you're referencing above:
before :each do
#account = Factory(:account, :user_id => Factory(:user).id, :profile_id => Factory(:profile).id)
end
Now #account will have #account.user and #account.profile available. If you need to define those, #profile = #account.profile works just great.

Not being able to order by includes on Rails3

I have the following expression:
user.clocks.includes(:users, :runs => :user_runs).find_by_id(params[:id])
which seems to work fine. But when I add an orders, like this:
user.clocks.includes(:users, :runs => :user_runs).orders("users.names").find_by_id(params[:id])
it breaks with the following error:
ActiveRecord::ConfigurationError: Association named 'user_runs' was not found; perhaps you misspelled it?
app/controllers/clocks_controller.rb:19:in `show'
test/functional/clocks_controller_test.rb:21:in `__bind_1286475263_942556'
Any ideas why?
The model looks like this:
class Clock < ActiveRecord::Base
has_and_belongs_to_many :users
has_many :runs
end
class Run < ActiveRecord::Base
belongs_to :clock
has_many :user_runs
has_many :users, :through => :user_runs
end
class UserRun < ActiveRecord::Base
belongs_to :run
belongs_to :user
end
Continuing with my investigation I've tried this:
ubiquitous_user.clocks.includes(:runs => :user_runs).find_by_id(params[:id])
and I've noticed the queries it's generating doesn't get user_runs at all. Something is odd.
I've created a set of tests to try to figure what was going on:
context "A graph of users, clocks, runs, etc" do
setup do
#users = []
10.times do
#users << Factory.create(:user)
end
#clocks = []
10.times do
#clocks << Factory.create(:clock, :users => #users)
end
#clocks.each do |clock|
10.times do
run = Factory.create :run, :clock => clock
#users.each do |user|
Factory.create :user_run, :run => run, :user => user
end
end
end
#user = #users.first
#clock = #clocks.first
end
should "find a clock" do
assert_not_nil #user.clocks.find(#clock.id)
end
should "find a clock with users" do
assert_not_nil #user.clocks.includes(:users).find(#clock.id)
end
should "find a clock with users and runs" do
assert_not_nil #user.clocks.includes(:users, :runs).find(#clock.id)
end
should "find a clock with users, runs and user_runs" do
assert_not_nil #user.clocks.includes(:users, :runs => :user_runs).find(#clock.id)
end
should "find a clock with users order by users.name" do
assert_not_nil #user.clocks.includes(:users).order("users.name").find(#clock.id)
end
should "find a clock with users and runs order by users.name" do
assert_not_nil #user.clocks.includes(:users, :runs).order("users.name").find(#clock.id)
end
should "find a clock with users, runs and user_runs order by users.name" do
assert_not_nil #user.clocks.includes(:users, :runs => :user_runs).order("users.name").find(#clock.id)
end
end
Every test but the last one pass. Is this not a bug?
Shouldn't it be
user.clocks.find_by_id(params[:id], :include => [:users, {:runs => :user_runs}])
?
I believe this is a bug, so I reported it here: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/5768

Testing an Rspec Controller with associations

I've got two models:
class Solution < ActiveRecord::Base
belongs_to :user
validates_attachment_presence :software
validates_presence_of :price, :language, :title
validates_uniqueness_of :software_file_name, :scope => :user_id
has_attached_file :software
end
class User < ActiveRecord::Base
acts_as_authentic
validates_presence_of :first_name, :last_name, :primary_phone_number
validates_uniqueness_of :primary_phone_number
has_many :solutions
end
with my routes looking like this:
map.resources :user, :has_many => :solutions
Now I'm trying to test my solutions controllers with the following RSpec test:
describe SolutionsController do
before(:each) do
#user = Factory.build(:user)
#solution = Factory.build(:solution, :user => #user)
end
describe "GET index" do
it "should find all of the solutions owned by a user" do
Solution.should_receive(:find_by_user_id).with(#user.id).and_return(#solutions)
get :index, :id => #user.id
end
end
end
However, this gets me the following error:
ActionController::RoutingError in 'SolutionsController GET index should find all of the solutions owned by a user'
No route matches {:id=>nil, :controller=>"solutions", :action=>"index"}
Can anybody point me to how I can test this, since the index should always be called within the scope of a particular user?
Factory#build builds an instance of the class, but doesn't save it, so it doesn't have an id yet.
So, #user.id is nil because #user has not been saved.
Because #user.id is nil, your route isn't activated.
try using Factory#create instead.
before(:each) do
#user = Factory.create(:user)
#solution = Factory.create(:solution, :user => #user)
end
Looks like your other problem is on this line:
get :index, :id => #user.id
You're trying to make a request to the index method, but you've provided the wrong variable name. When testing SolutionsController id implies a solution id, you need to supply the user id. This should work, or at least move you forward:
get :index, :user_id => #user.id

Resources