While testing Devise with rspec, it acts like I am not logged in - ruby-on-rails-3

I'm using Rails 3.2.13, devise 2.2.4, and rspec 2.13.2. I have a multi-tenant app in which the default scope only shows current_user's items. Everything seems to work in development, but my tests are having issues.
Problem: When I create a meal in my test, it shows user_id => nil. In my development environment everything works, though. Also, when I go into debug mode, when I check the #controller.current_user, it shows user_id 1 is logged in. Since in my development environment the user_id is being assigned automatically when I create an object, I can't figure out why it's not doing it during tests. Any ideas?
Here's my abbreviated meals_controller_spec file:
describe MealsController do
include Devise::TestHelpers
describe "When logged in as user," do
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
#email = "someone#test.com"
#password = "password"
#user = User.create(email: #email, password: #password)
sign_in #user
end
describe "DELETE destroy" do
it "destroys the requested meal" do
meal = Meal.create!("name" => "", "servings" => "2", "meal_type" => "dinner")
expect { delete 'destroy', {:id => meal.id} }.to change(Meal, :count).by(-1)
end
end
end
end
Here's part of my model:
class Meal < ActiveRecord::Base
belongs_to :user
default_scope { where(user_id: User.current_id) }
Here's part of my controller:
class MealsController < ApplicationController
before_filter :authenticate_user!
def destroy
#meal = Meal.find(params[:id])
#meal.destroy
redirect_to meals_url, :notice => "Successfully deleted #{#meal.name}."
end
end
And I think my application controller could be relevant:
class ApplicationController < ActionController::Base
protect_from_forgery
around_filter :scope_current_tenant
private
def scope_current_tenant
User.current_id = current_user.id
yield
rescue Exception
yield
ensure
User.current_id = nil
end
end
Here's some output when I debug in the middle of that test:
(rdb:1) #controller.current_user.id
1
(rdb:1) Meal.create!(name: "meal", meal_type: "dinner", servings: 2)
#<Meal id: 2, name: "meal", meal_type: "dinner", servings: 2, user_id: nil, created_at: "2013-06-17 06:07:34", updated_at: "2013-06-17 06:07:34">
(rdb:1) Meal.create!(name: "meal", meal_type: "dinner", servings: 2, user_id: 1)
#<Meal id: 3, name: "meal", meal_type: "dinner", servings: 2, user_id: 1, created_at: "2013-06-17 06:12:18", updated_at: "2013-06-17 06:12:18">
(rdb:1) Meal.find(3).destroy
*** NoMethodError Exception: undefined method `destroy' for nil:NilClass
So I guess I'm wondering why the user in my test appears to be nil, even though I am using the Devise test helpers and signing in, and in my dev environment everything works.
Edit:
Here are some more debugger results:
(rdb:1) Meal.find(4)
*** ActiveRecord::RecordNotFound Exception: Couldn't find Meal with id=4 [WHERE "meals"."user_id" IS NULL]
(rdb:1) Meal.find(4).destroy
*** ActiveRecord::RecordNotFound Exception: Couldn't find Meal with id=4 [WHERE "meals"."user_id" IS NULL]
(rdb:1) Meal.where(:user_id => 1).find(3)
#<Meal id: 3, name: "meal", meal_type: "dinner", servings: 2, user_id: 1, created_at: "2013-06-17 06:12:18", updated_at: "2013-06-17 06:12:18">
It appears that the "current user" is in fact user_id => nil, per the sql snippets. So why would that be if I used the Devise test helper sign_in function?

Related

Ruby on Rails 4: has_secure_password is not asking for a password confirmation when creating new user

I am currently writing an app using RoR4 and am having trouble with authentication. Even though I've added has_secure_password to the User model, I still seem to be able to create a new user without having to provide a password confirmation.
2.1.2 :012 > me = User.create(:institution_id => 1, :email => "me#myschool.edu", :password => "mypassword")
(0.1ms) BEGIN
User Exists (0.3ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = BINARY 'me#myschool.edu' LIMIT 1
SQL (0.2ms) INSERT INTO `users` (`created_at`, `email`, `institution_id`, `password_digest`, `updated_at`) VALUES ('2014-07-14 20:02:34', 'me#myschool.edu', 1, '$2a$10$sD2N.2nxhYO7egzzWxfF5.cdIZ4ds41.sU93Ja3E9Q0qAOaABdZb6', '2014-07-14 20:02:34')
(8.2ms) COMMIT
=> #<User id: 5, institution_id: 1, first_name: nil, last_name: nil, email: "me#myschool.edu", blurb: nil, facebook_link: nil, facebook_token: nil, password_digest: "$2a$10$sD2N.2nxhYO7egzzWxfF5.cdIZ4ds41.sU93Ja3E9Q0...", api_key: nil, active: false, created_at: "2014-07-14 20:02:34", updated_at: "2014-07-14 20:02:34", authentication_token: nil>
Why is this happening? Shouldn't has_secure_password always require a password confirmation as well??
Thanks for the help
Make sure you followed these things:
add gem 'bcrypt' to gem file.
Next:
have a password_digest attribute
Next:
class User < ActiveRecord::Base
has_secure_password
end
Then you can test it:
user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
user.save # => false, password required
user.password = 'mUc3m00RsqyRe'
user.save # => false, confirmation doesn't match
user.password_confirmation = 'mUc3m00RsqyRe'
user.save # => true
user.authenticate('notright') # => false
user.authenticate('mUc3m00RsqyRe') # => user
User.find_by(name: 'david').try(:authenticate, 'notright') # => false
User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user

CanCan abilities working in application but not in test

I have the following definition in my ability.rb file:
can :index, Call, :country_id => user.countries
I am trying to only index Calls whose country_id is in current user's countries array.
This seems to be working when I try it: It only shows me calls that have been tagged by countries that the current_user is a member of.
However, I have the following test which I can't seem to get to pass:
before :each do
# Users
#admin = FactoryGirl.create(:user, admin: true)
end
it "should show the call index page with just calls that have the same country tags as them" do
anotheruser1 = FactoryGirl.create(:user)
anotheruserscall1 = FactoryGirl.create(:call, user_id: anotheruser1.id)
anotheruser2 = FactoryGirl.create(:user)
anotheruserscall2 = FactoryGirl.create(:call, user_id: anotheruser2.id)
#admin.countries << anotheruserscall1.country
ability = Ability.new(#admin)
ability.should be_able_to(:index, anotheruserscall1)
ability.should_not be_able_to(:index, anotheruserscall2)
end
But I get a failure:
Failures:
1) Admin ability should show the call index page with just calls that have the same country tags as them
Failure/Error: ability.should be_able_to(:index, anotheruserscall1)
expected to be able to :index #<Call id: 1, subject: "Natus qui fuga ut.", description: "Consequatur aut veritatis earum dolor. Reprehenderi...", from: "2012-10-25 18:43:23", to: "2012-10-25 19:43:23", user_id: 7, status: "Tentative", created_at: "2012-10-29 13:41:07", updated_at: "2012-10-29 13:41:07", expert_id: nil, country_id: 1>
# ./spec/models/ability_spec.rb:291:in `block (2 levels) in <top (required)>'
Any help greatly appreciated.
OK, I fixed this by passing the details in as a block as follows:
can :index, Call, ["country_id IN (?)", user.countries] do |call|
user.countries.include?(call.country)
end

Rails :include doesn't include

My models:
class Contact < ActiveRecord::Base
has_many :addresses
has_many :emails
has_many :websites
accepts_nested_attributes_for :addresses, :emails, :websites
attr_accessible :prefix, :first_name, :middle_name, :last_name, :suffix,
:nickname, :organization, :job_title, :department, :birthday,
:emails_attributes
end
class Email < ActiveRecord::Base
belongs_to :contact
validates_presence_of :account
validates_format_of :account, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
attr_accessible :contact_id, :account, :label
end
If I run the following query, the emails are returned as expected:
c = Contact.find(3)
Contact Load (3.2ms) SELECT `contacts`.* FROM `contacts` LIMIT 1
=> #<Contact id: 3, prefix: nil, first_name: "Micah", middle_name: nil, last_name: "Alcorn", suffix: nil, nickname: nil, organization: nil, job_title: nil, department: nil, birthday: nil, created_at: "2011-07-04 23:50:04", updated_at: "2011-07-04 23:50:04">
c.emails
Email Load (4.4ms) SELECT `emails`.* FROM `emails` WHERE `emails`.`contact_id` = 3
=> [#<Email id: 3, contact_id: 3, account: "not#real.address", label: "work", created_at: "2011-07-04 23:50:04", updated_at: "2011-07-04 23:50:04">]
However, attempting to :include the relationship does not:
c = Contact.find(3, :include => :emails)
Contact Load (0.5ms) SELECT `contacts`.* FROM `contacts` WHERE `contacts`.`id` = 3 LIMIT 1
Email Load (0.8ms) SELECT `emails`.* FROM `emails` WHERE `emails`.`contact_id` IN (3)
=> #<Contact id: 3, prefix: nil, first_name: "Micah", middle_name: nil, last_name: "Alcorn", suffix: nil, nickname: nil, organization: nil, job_title: nil, department: nil, birthday: nil, created_at: "2011-07-04 23:50:04", updated_at: "2011-07-04 23:50:04">
As you can see, the SQL is being executed, but the emails are not being returned. I intend to return all contacts with each containing email(s), so :joins won't do any good. What am I missing?
The emails are there. Did you try c.emails? You will find that the emails will be there without Rails doing an additional DB query.
The thing that :include does is called eager loading, which basically means Rails will try a best effort method of prepopulating your objects with their relations, so that when you actually ask for the relation no additional DB queries are needed.
See the section "Eager loading of associations" here:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
You might also want to check out this RailsCast:
http://railscasts.com/episodes/181-include-vs-joins

Rails 3 + Rspec 2: Validation failed: Email has already been taken

I have 2 models, User and Bucket. User has_many Buckets and a Bucket belongs_to a User.
In factories.rb, I have:
Factory.define :user do |user|
user.email "teste#test.com"
user.password "foobar"
user.password_confirmation "foobar"
end
Factory.sequence :email do |n|
"person-#{n}#example.com"
end
Factory.define :bucket do |bucket|
bucket.email "user#example.com"
bucket.confirmation false
bucket.association :user
end
and I have a login_user module as follows:
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
#user = Factory.create(:user)
##user.confirm!
sign_in #user
end
end
I am using Spork and Watch and my Buckets_controller_spec.rb is as simple as:
describe "User authenticated: " do
login_user
#bucket = Factory(:bucket)
it "should get index" do
get 'index'
response.should be_success
end
...
end
The error is always the same:
Failures:
1) BucketsController User authenticated: should get index
Failure/Error: Unable to find matching line from backtrace
ActiveRecord::RecordInvalid:
Validation failed: Email has already been taken
# ./lib/controller_macros.rb:12:in `block in login_user'
And it only happens when I have the Factory(:bucket). The login works fine when I don't add the Factory(:bucket).
It's always the same error. I have tried adding :email => Factory.next(:email) to the user, but no success.
Edit:
In rails c test:
ruby-1.9.2-p180 :019 > bucket = Factory(:bucket, :email => "hello#hello.com")
ActiveRecord::RecordInvalid: Validation failed: Email has already been taken
ruby-1.9.2-p180 :018 > Bucket.create(:email => "hello#hello.com")
=> #<Bucket id: 2, email: "hello#hello.com", confirmation: nil, created_at: "2011-04-08 21:59:12", updated_at: "2011-04-08 21:59:12", user_id: nil>
Edit 2:
I found out that the error is in the association, however, I don't know how to fix it.
bucket.association :user
When you define a factory with an association you need to give the factory an object to associate with whenever you use the factory.
This should work:
describe "User authenticated: " do
login_user
#bucket = Factory(:bucket, :user => #user)
it "should get index" do
get 'index'
response.should be_success
end
end
That way factorygirl knows to make a bucket which is associated with #user.
Try this in your user factory:
Factory.define :user do |f|
f.sequence(:email) { |n| "test#{n}#example.com" }
...
end
I think that's probably your problem. When you use f.email = "anyvalue" it's going to use that value every time. I see you were trying to create a sequence in the next block, but I'm not sure that sequence is getting used.
ALSO - be aware that if you get tests interrupted by a crash or something, sometimes bogus test data can get left in your test DB instead of being rolled back.
Very first thing I try if something worked once and then quit working is to reset the test db.
rake db:test:prepare
That will clean everything out.
If this doesn't work let me know and I'll take a second look!
If someone is getting this recently with your views. Try using Database Cleaner.
For more info: RailsTutorial - chapter 8.4.3 - Test database not clearing after adding user in integration test

How to create a nested form in Rails 3 that works? ( I'm getting a routing error. )

I have a Client and ProposalRequest model that look like this:
class Client < ActiveRecord::Base
has_many :proposal_requests
accepts_nested_attributes_for :proposal_requests, :allow_destroy => true
end
class ProposalRequest < ActiveRecord::Base
belongs_to :client
end
In my my routes file, I included the nested routes, as usual.
resources :clients do
resources :proposal_requests
end
And this is my form so far:
-semantic_form_for [Client.new, ProposalRequest.new] do |f|
=f.inputs
=f.buttons
But after this, I'm stuck because of this error.
No route matches {:controller=>"proposal_requests", :client_id=>#<Client id: nil, name: nil, title: nil, organization: nil, street_address: nil, city: nil, state: nil, zip: nil, phone: nil, email: nil, status: "interested", how_you_heard: nil, created_at: nil, updated_at: nil>}
Can anyone help me puzzle out this error?
The problem is that your nested route is meant to add a new ProposalRequest to an existing Client. If you want to create a Client and a ProposalRequest at the same time, you need to just use new_client_path and semantic_form_for #client do |f|.
I would recommend you do the following in your clients_controller:
def new
#client = Client.find(params[:id])
#client.proposal_requests.build
end
And in your view:
semantic_form_for #client do |f|
= f.inputs # fields for client
= f.inputs :name => 'Proposal Request', :for => :proposal_requests do |pf|
= pf.input :some_proposal_request_attribute
= f.buttons
Hope this helps. Make sure to look at all the examples at https://github.com/justinfrench/formtastic and do some trial and error to get your form how you want it.