Closed empimp closed 13 years ago
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”
@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
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
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.
@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.
@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 - https://github.com/plataformatec/devise/issues/1192 .
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 https://github.com/plataformatec/devise/issues/1192#issuecomment-1536551).
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.
josevalim changed the default behavior on 27 June 2011 for Devise version 1.4.1. Here's the commit:
https://github.com/plataformatec/devise/commit/adb127bb3e3b334cba903db2c21710e8c41c2b40
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."
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?
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.
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.
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?
@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.
@ches, thanks for suggesting click_link
and providing the additional info.
Welcome, thanks for the detailed tutorials :-)
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: https://github.com/guard/guard-rspec/issues/93
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)
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
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:
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:in
show' (eval):2:inclick_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.
Thanks, in advance, for any help troubleshooting this problem!