Couldn't find User with id=sign_out (ActiveRecord::RecordNotFound) #3

Closed
empimp opened this Issue Jul 6, 2011 · 18 comments

Projects

None yet
@empimp
empimp commented Jul 6, 2011

Thanks for a great tutorial!

After I finished going through it, I was still having rspec and cucumber issues. I've since tracked down and corrected most of my typos :-) Unfortunately I've run into two cucumber failures, that appear to me to be related, but I have run out of google (actually duckduckgo,com, google, & stackoverflow) troubleshooting mojo. Any troubleshooting guidance would be very much appreciated.

The first error impacts the following three scenarios:

  • User signs in successfully with email
  • User signs out
  • I sign in and edit my account

While the second impacts the, "User signs up with valid data" scenario.

My own troubleshooting has led me to believe that the problem is actually sign_out functionality, specifically as it relates to testing. One reason I believe this is the commonality between the errors:
Couldn't find User with id=sign_out (ActiveRecord::RecordNotFound) ./app/controllers/users_controller.rb:5:inshow'
(eval):2:in click_button'
The other reason is that I was able to manually replicate these errors until I inserted the missing :method => 'delete' statement on the 'Logout' function of app/views/devise/menu/_login_items.html.erb.

I modified my sign_up.feature, but the other feature and step_definition files are unmodified copy/pastes from your repository.

The cucumber error messages, as well as the sign_up.feature, user_controller.rb, and web_steps.rb are available at https://gist.github.com/1066257.

<script src="https://gist.github.com/1066257.js"> </script>

Thanks, in advance, for any help troubleshooting this problem!

@fortuity
Contributor
fortuity commented Jul 6, 2011

Is your issue the same as this one reported on StackOverflow?

Rails 3.0.9 + Devise + Cucumber + Capybara the infamous “No route matches /users/sign_out”

@empimp
empimp commented Jul 6, 2011

@fortuity - I didn't replace prototype with jquery, so I didn't make the first change listed in Zeeshan's question, but I did try every subsequent change he made in both his question and answer, and still get the same errors.

If I understand most of what he's sayng (which is a big 'If') then his problem is tied directly to his use of jquery (e.g., he states "jquery_ujs.js has following method to convert the links with data-method="delete" attribute to a form and submit at runtime:")

And his cucumber failures were on the actual sign_out steps. My cucumber failures are are on four different steps, only one of which is a sign_out step, but for each of those failures the cucumber failure message includes the following:

Couldn't find User with id=sign_out (ActiveRecord::RecordNotFound)
./app/controllers/users_controller.rb:5:in `show'
(eval):2:in `click_button' 

I've uploaded my app to https://github.com/empimp/swabbie_pre-alpha/tree/feature/auth_and_auth

@empimp empimp closed this Jul 6, 2011
@empimp empimp reopened this Jul 6, 2011
@cailinanne

I'm having the same problem. I have made no modifications to the start app. Just created it with

rails new demo -m https://github.com/RailsApps/rails3-application-templates/raw/master/rails3-devise-rspec-cucumber-template.rb -T
@cailinanne

Okay, I've spent some time investigating this.

The fundamental issue is that the application code provided just doesn't jive with the routes that are generated by Devise. This is a gem version issue. Back in Devise 1.3.2 a GET route was provided for destroy_user_session_path, but now only a DELETE route is provided. I have no idea when that changed, but that's the core issue here.

The easiest way to "get this working" is to force the routes to match the application. You can do this by modifying the routes file.

Remove:

devise_for :users

Add:

devise_for :users do
  get "/users/sign_out" => "devise/sessions#destroy", :as => :destroy_user_session
end

This is a bit dirty. I'm sure that Devise deprecated the GET route for good reason. However, fixing it any other way is beyond my Cucumber knowledge at this point, as every test in that suite ultimately relies on visit('/users/logout') which just isn't possible with the out-of-the-box Devise routes.

@fortuity
Contributor
fortuity commented Jul 8, 2011

@empimp and @cailinanne thanks for investigating and reporting the issue. I'm going to wait to take any action until I see if there is any change to Devise or Cucumber to accommodate this problem.

@empimp
empimp commented Jul 8, 2011

@cailinanne - Thank you for providing a work-around, getting me to a green cucumber, and restoring my newb sanity!

@fortuity and @cailinanne - Since it does seem like a Devise version issue, and I didn't see any reference of it in the Devise documentation or the issue log I opened a new issue and posted a linkback to this thread - plataformatec/devise#1192 .

@eidosabi
eidosabi commented Jul 9, 2011

josevalim responded that "The default in a newly generated app is to only work with a DELETE. But there is a configuration option to change that in config/initializers/devise.rb" (over in plataformatec/devise#1192 (comment)).

Using the routes.rb in the tutorial AND commenting out config.sign_out_via = :delete in /config/initializers/devise.rb gives me a green cuc. :-) I've updated the tutorial accordingly.

@fortuity
Contributor
fortuity commented Jul 9, 2011

josevalim changed the default behavior on 27 June 2011 for Devise version 1.4.1. Here's the commit:

plataformatec/devise@adb127b

He explains:

"GET requests should not change the state of the server. When sign out is a GET request, CSRF can be used to sign you out automatically and things that preload links can eventually sign you out by mistake as well."

@eidosabi
eidosabi commented Jul 9, 2011

I updated the wiki tutorial to read:

In /config/initializers/devise.rb you will also need to comment out @config.sign_out_via = :delete@:

# The default HTTP method used to sign out a resource. Default is :delete.
# config.sign_out_via = :delete

According to josevalim's comment this isn't the best way to handle this, and @cailinanne said her method was "a bit dirty", so what is the recommended way to use the default Devise sign_out?

@fortuity
Contributor
fortuity commented Jul 9, 2011

Cucumber wants to test GET requests not DELETE requests for destroy_user_session_path. If you intend to use Cucumber with Devise, change the Devise default from DELETE to GET for the Rails test environment only with this change to config/initializers/devise.rb:

config.sign_out_via = Rails.env.test? ? :get : :delete

Don't try to tweak the routes.rb file to make the fix. It isn't necessary.

Since you only use Cucumber during testing, switching the default is only needed for testing.

If you're not going to use Cucumber, leave Devise's new default (DELETE) in place.

I haven't raised this issue with the Cucumber experts (I'm curious what they will suggest). You may want to discuss it with them. If you gather more information, please bring it back here.

I've updated the application template and the Rails Apps Composer gem to detect the collision between Devise and Cucumber and the template will make the change to the the Devise initializer when Cucumber is included. The example source code now implements the change. I will review and update the tutorial as well.

Thank you, everyone, for contributing to resolution of this issue.

@fortuity fortuity closed this Jul 9, 2011
@doolin
doolin commented Jul 10, 2011

I found this same problem and more or less the same fix independently last week. It's definitely real. I haven't quite figured out which list (cucumber or devise) to describe too.

@schadenfred
Contributor

It seems like this is fundamentally a problem with Capybara, and that Capybara should be forced to accept the :delete method. Has anyone tried this?

@ches
ches commented Aug 1, 2011

@fortuity I commented on the Stack Overflow thread you referenced above, but I think you should update the tutorial (and Devise wiki page on the topic!) -- sidestepping the changes that were made to Devise is not a good solution!

The quick answer is to make the "sign out" step definition use click_link so that cucumber-rails' magical JS emulation for Capybara steps in to handle things. The better but more involved answer I think is to use button_to for the logout as the OP arrived at on the SO thread. There is discussion relevant to both on this old Capybara issue.

@DanielKehoe
Member

@ches, thanks for suggesting click_link and providing the additional info.

@ches
ches commented Aug 2, 2011

Welcome, thanks for the detailed tutorials :-)

@stanley71

Had this issue as well. Turned out to be an issue with my guard was running my tests in development environment instead of test. This is why the check in the devise.rb initalizer didn't work for me. Took me quite some time to discover this one! Maybe some newbie like me is facing this problem as well, so this could help. Found my solution thanks to this post: guard/guard-rspec#93

@evedovelli

The right way to use Capybara with Devise is explained in devise's wiki: https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara

Once you have included on your user_step.rb file:

include Warden::Test::Helpers
Warden.test_mode!

You may replace visit '/users/sign_out' with logout(:user)

@harrisjb harrisjb pushed a commit to harrisjb/socialoffice-workout that referenced this issue Feb 28, 2014
Josh commenting out config.sign_out_via :delete per suggestion at RailsApp…
…s/rails3-devise-rspec-cucumber#3 to prevent error ActiveRecord::RecordNotFound Couldnt find UserProfile with ID=sign_out
ac87148
@Ruby4Life

I had the same issue

I noticed that I had java script disabled on my browser!

I enabled JS on my browser

And all is well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment