This started out as a problem I could not get past in the rails tutorial, but at this point I would just like to understand whats going on, if I can I should be able to get past my problem in the tutorial.
My problem boils down to this. I am trying to set a cookie in a test, and then check it's value in the controller after doing a put, but I don't see the cookie in the controller.
Here is the code in the test:
describe "as wrong user" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
before do
puts "setting up test - set remeber_token"
cookies['remember_token'] = user.remember_token
puts "cookies['remember_token'] = #{cookies['remember_token']}"
end
describe "submitting a PUT request to the Users#update action" do
before do
puts "in test "
puts "cookies['remember_token'] = #{cookies['remember_token']}"
put user_path(wrong_user)
end
specify { response.should redirect_to(root_url) }
end
end
and here is the code in the controller (I think this is all that is relevant)
before_filter :signed_in_user, only: [:edit, :update]
before_filter :correct_user, only: [:edit, :update]
def signed_in_user
puts "in signed_in_user filter"
puts "cookies['remember_token'] = #{cookies['remember_token']}"
redirect_to signin_url, notice: "Please sign in." unless signed_in?
end
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless current_user?(@user)
end
When I run the tests the output seems to indicate that the cookie is set in the test but is gone in the before filter. The test ultimately fails because because the signed_in?
method is supposed to see if a user exists with the remember_token retrieved from the cookies object, which is nil. Can someone explain what is going on here?
Here is the console output:
>bundle exec rspec spec/requests/authentication_pages_spec.rb -e "submitting a PUT request to the Users#update action"
Run options: include {:full_description=>/submitting\ a\ PUT\ request\ to\ the\ Users\#update\ action/}
setting up test - set remeber_token
cookies['remember_token'] = qpcZCCuhaoBirjWR9s5YMw
in test
cookies['remember_token'] = qpcZCCuhaoBirjWR9s5YMw
in signed_in_user filter
cookies['remember_token'] =
F
Failures:
1) Authentication authorization as wrong user submitting a PUT request to the Users#update action
Failure/Error: specify { response.should redirect_to(root_url) }
Expected response to be a redirect to <"http://www.example.com/"> but was a redirect to <"http://www.example.com/signin">
# ./spec/requests/authentication_pages_spec.rb:84:in `block (5 levels) in <top (required)>'
Finished in 0.34502 seconds
1 example, 1 failure
Failed examples:
rspec ./spec/requests/authentication_pages_spec.rb:84 # Authentication authorization as wrong user submitting a PUT request to the Users#update action
UPDATE: I tried using request.cookies['remember_token'] to set the cookie in the test and retrieve in the before filter, and I am having the same issue.
so basically I have this:
describe "as wrong user" do
describe "in the Users controller" do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
before do
puts "setting up test - set remeber_token"
get root_url
request.cookies['remember_token'] = user.remember_token
puts "cookies['remember_token'] = #{request.cookies['remember_token']}"
end
describe "visiting Users#edit page" do
before { visit edit_user_path(wrong_user) }
it { should_not have_selector('title', text: full_title('Edit user')) }
end
describe "submitting a PUT request to the Users#update action" do
before do
puts "in test "
puts "cookies['remember_token'] = #{request.cookies['remember_token']}"
put user_path(wrong_user)
end
specify { response.should redirect_to(root_url) }
end
end
and in the before_filter :
def signed_in_user
puts "in signed_in_user filter"
puts "cookies[:remember_token] = #{request.cookies[:remember_token]}"
puts "request = #{request.cookies}"
p request
redirect_to signin_url, notice: "Please sign in." unless signed_in?
end
and the puts "request = #{request.cookies}"
returns => request = {}
Update:
I now understand what is going on here. I have too look back through the tutorial to see if I missed something, or find the correct way around this. Here is what is happening.
In the ApplicationController I have this (copied directly from the tutorial)
class ApplicationController < ActionController::Base
protect_from_forgery
include SessionsHelper
# Force signout to prevent CSRF attacks
def handle_unverified_request
sign_out
super
end
end
The sessions helper has this sign_out method:
def sign_out
puts "in sign out"
cookies.delete :remember_token
self.current_user = nil
end
So what happens is that when I do the put in the test, the user gets signed out and as a result is redirected to the sign in page rather than the root_url. I have to look through the tutorial to see what I might have missed, or maybe it's an oversight?
SOLVED!
It turns out this was a very simple set up issue in my environment. I had set the environment variable RAILS_ENV="development". Removing that allows the first line in the spec_helper.rb to correctly set the RAILS_ENV to 'test' which turns protect_from_forgery off in the test env, which prevents the sign_out when I do the put, and allows the test to pass.
I doubt many others will have this same issue, but if you are going through the rails tutorial and are failing the following test, make sure your tests are being run in the test environment.
Failures:
1) Authentication authorization as wrong user submitting a PUT request to the Users#update action
Failure/Error: specify { response.should redirect_to(root_url) }
Expected response to be a redirect to <"http://www.example.com/"> but was a redirect to <"http://www.example.com/signin">
# ./spec/requests/authentication_pages_spec.rb:84:in `block (5 levels) in <top (required)>'