Rails 3 with Devise: No route matches /d/users/sign_out - ruby-on-rails

I am getting the following error when I try to sign out of devise error:
No route matches [GET] "/d/users/sign_out"
My tag is correct, it is as follows:
<%= link_to "Sign Out", destroy_session_path, :method=>:delete %>
My route for devise is:
devise_for :users, :path_prefix=>"d", :controllers=>{:sessions=>"sessions"}
Other routes are:
resources :users#For CRUD defined after devise_for like in Devise Wiki
With a custom controller sessions for ajax login like on the Devise wiki page:
class SessionsController < Devise::SessionsController
def create
respond_to do |format|
format.html{ super }
format.json do
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
#resource = warden.authenticate!(:scope => resource_name, :recall => :failure)
return sign_in_and_redirect(resource_name, resource)
end
end
end
def sign_in_and_redirect(resource_or_scope, resource=nil)
scope = Devise::Mapping.find_scope!(resource_or_scope)
resource ||= resource_or_scope
sign_in(scope, resource) unless warden.user(scope) == resource
return render :json => {:success => true, :redirect => stored_location_for(scope) || after_sign_in_path_for(resource)}
end
def failure
return render:json => {:success => false, :errors => ["Login failed."]}
end
end
The devise initializer has:
config.sign_out_via = :delete
Any ideas on what could be causing the problem? I've searched Google and am still stumped.
Update:
Here is a screenshot of the rails routes file for the devise users. Sorry, it is small, but you can right-click then view it by itself for a larger screen.
Update #2:
The jquery_ujs file is included.
Update #3:
It appears in the console that delete is indeed being passed, but it is jumping from the sessions_controller to / then to d/users/sign_out...Not sure how to fix this.
Update #4:
When redirecting it goes first to d/users/sign_out as DELETE, as it should. It then redirects to root_url which then gives the error ERROR Errno::ECONNABORTED: An established connection was aborted by the software in your host machine. It then tries to redirect to d/users/sign_out as GET where it is failing.

This appears to be an issue between Devise and Ruby 1.9.2-p290. Updating to Ruby 1.9.3 and running bundle update to ensure the latest version of Devise was used; appears to work.

It sounds like you might have removed //= require jquery_ujs from your application.js file. I think that handles the link particulars to make a 'delete' request. Either way, as it is now, you're making a 'GET' which obviously won't hit your destroy_user_session method.

Change:
config.sign_out_via = :delete
to:
config.sign_out_via = :get
See this related:
No route matches "/users/sign_out" devise rails 3

Related

How to use custom view to update user via devise? (rails gem)

I have 2 custom views I built for devise, 1 changes the password the other updates other custom information. The password update worked, so I copied the method for the second view, however I am getting an error when submitting the data
No route matches [PATCH] "/users/discovery_settings/update"
which does not make sense because my route is
devise_for :users, controllers: {registrations: 'users/registrations'}
as :user do
end
get 'users/discovery_settings' => 'users#discovery_settings'
post 'users/discovery_settings/update' => 'users#update_discovery'
in my controller i user the same method that works for password updates
def update_discovery
#user = User.find(current_user.id)
if #user.update(user_params)
# Sign in the user by passing validation in case their password changed
sign_in #user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
then i call it in my form_for view
<%= form_for(#user, :url => { :action => "update_discovery" }, html: {class: "form floating-label"}) do |f| %>
Any ideas how to fix the routing error?
I am at a lost as to why it is looking for "patch" when i have already specified "post"
The error's telling you. You have a POST route and the update is asking for a PATCH route.
try with patch instead of post:
patch 'users/discovery_settings/update' => 'users#update_discovery'

Trying to override controller in Thoughtbot's Clearance gem for Rails

I am using Clearance 1.1.0 gem with Ruby on Rails 4.0.1. I am trying to override the sessions controller to provide my own custom method. I have not been able to successfully get rails to use my controller.
/app/controllers/sessions_controller.rb
class SessionsController < Clearance::SessionsController
private
def flash_failure_after_create
flash.now[:notice] = translate(:bad_email_or_password,
:scope => [:clearance, :controllers, :sessions],
:default => t('flashes.failure_after_create', :new_password_path => new_password_path).html_safe)
end
end
I have tried a few different things inside my routes.rb file, and have been unsuccessful. I want to change the route sign_in.
get '/sign_in' => 'sessions#new', :as => 'sign_in'
Yields the following error.
You may have defined two routes with the same name using the :as
option, or you may be overriding a route already defined by a resource
with the same naming.
Any ideas? Thank you!
Edit: I made a mistake. I actually need sessions#create to use my controller. I'm trying to pass a different variable to the yaml file for the flash when the session login fails.
Edit 2: I the appropriate session#create line to to my routes. In my session controller, I copied and edited for testing the flash_failure_after_create method. It is not being called. So I then copy the create method over. Now, my create method is being called, but not my flash_failure_after_create method. To get it to be called, I had to have the create method copied from gem, and changed status.failure_message to directly call the flash_failure_after_create method. Is this some sort of bug with clearance?
routes.rb
post 'session' => 'sessions#create', :as => nil
sessions_controller.rb
class SessionsController < Clearance::SessionsController
def create
#user = authenticate(params)
sign_in(#user) do |status|
if status.success?
redirect_back_or url_after_create
else
#flash.now.notice = status.failure_message
flash.now.notice = flash_failure_after_create
render :template => 'sessions/new', :status => :unauthorized
end
end
end
private
def flash_failure_after_create
# Changed flash for easy testing
flash.now[:notice] = 'Ballz.'
#flash.now[:notice] = translate(:bad_email_or_password,
# :scope => [:clearance, :controllers, :sessions],
# :default => t('flashes.failure_after_create', :sign_up_path => sign_up_path).html_safe)
end
end
I believe this will work:
get '/sign_in' => 'sessions#new', :as => nil
Rails 4 no longer supports overriding route names, so don't name your override. The mapping is still the same so sign_in_path should still work.

How can I customize Devise's "resend confirmation email"

I have a custom mailer (UserMailer.rb) and a few methods to override the default Devise methods for the welcome email and forgot password emails. The mailer uses a custom template to style the emails--and it works great.
In config/initializers, I have a file with
module Devise::Models::Confirmable
# Override Devise's own method. This one is called only on user creation, not on subsequent address modifications.
def send_on_create_confirmation_instructions
UserMailer.welcome_email(self).deliver
end
...
end
(Again, UserMailer is setup and works great for the welcome email and reset password email.)
But what's not working is the option to "Resend confirmation instructions." It sends with the default Devise styling and I want it to use the styling of my mailer layout. I know I can manually add the layout to the default Devise layout, but I'd like to keep DRY in effect and not have to do that.
I've tried overriding the send_confirmation_instructions method found here, but I'm getting a wrong number of arguments (1 for 0) error in create(gem) devise-2.2.3/app/controllers/devise/confirmations_controller.rb at
7 # POST /resource/confirmation
8 def create
9 self.resource = resource_class.send_confirmation_instructions(resource_params)
In my initializer file, I'm able to get to this error by adding a new override for Devise, but I'm probably not doing this correctly:
module Devise::Models::Confirmable::ClassMethods
def send_confirmation_instructions
UserMailer.send_confirmation_instructions(self).deliver
end
end
Any ideas?
You don't have to go through that initializer to do that. I've done this by overriding the confirmations controller. My routes for devise look like:
devise_for :user, :path => '', :path_names => { :sign_in => 'login', :sign_out => 'logout', :sign_up => 'signup'},
:controllers => {
:sessions => "sessions",
:registrations => "registrations",
:confirmations => "confirmations"
}
Then, create the confirmations_controller and extend the Devise::ConfirmationsController to override:
class ConfirmationsController < Devise::ConfirmationsController
In that controller, I have a create method to override the default:
def create
#user = User.where(:email => params[:user][:email]).first
if #user && #user.confirmed_at.nil?
UserMailer.confirmation_instructions(#user).deliver
flash[:notice] = "Set a notice if you want"
redirect_to root_url
else
# ... error messaging or actions here
end
end
Obviously, in UserMailer you can specify the html/text templates that will be used to display the confirmation message. confirmation_token should be a part of the #user model, you can use that to create the URL with the correct token:
<%= link_to 'Confirm your account', confirmation_url(#user, :confirmation_token => #user.confirmation_token) %>

Rails: DoubleRenderError - "Render and/or redirect were called multiple times in this action"

I want to redirect by the role_ids of the user:
If it's equal to 2, redirect to workers_path.
if it's equal to 1, redirect to tasksadmins_path.
I defined the next things:
class ApplicationController < ActionController::Base
include ApplicationHelper
protect_from_forgery
before_filter :authenticate_user!
def stored_location_for(user)
nil
end
def after_sign_in_path_for(user)
if current_user.role_ids == [2]
return redirect_to(workers_path)
else
return redirect_to (tasksadmins_path)
end
end
end
but when I sign in, I got errors:
AbstractController::DoubleRenderError in UserSessionsController#create
Render and/or redirect were called multiple times in this action. Please note
that you may only call render OR redirect, and at most once per action. Also
note that neither redirect nor render terminate execution of the action, so
if you want to exit an action after redirecting, you need to do something
like "redirect_to(...) and return".
Rails.root: /home/alon/alon/todolist
Application Trace | Framework Trace | Full Trace
app/controllers/user_sessions_controller.rb:5:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"jRNZkIXvToEhl9YVxaQoa2hLJiSaHI6JAdfpUNAQMJI=",
"user"=>{"email"=>"worker216#gmail.com",
"password"=>"[FILTERED]",
"remember_me"=>"0"},
"commit"=>"Sign in"}
This is my user_session_controller.rb:
class UserSessionsController < Devise::SessionsController
include ApplicationHelper
def create
response = super
require "uri"
require "net/http"
## get the user id from the database
user_id = session['warden.user.user.key'][1][0];
## get the row by id
user = User.find(user_id)
# ============================
# Ensure that a user exists
# ============================
code, body = http_request(Net::HTTP::Put.new("/api/v1/users/external/#{user_id}"), email: user.email);
if code != 200
Rails.logger.error("Unable to register user #{current_user.email} at Licensario");
end
response
end
end
and this is my routes.rb:
TODOLIST::Application.routes.draw do
devise_for :users, :controllers => { :sessions => 'user_sessions'} do
get '/users/sign_out' => 'devise/sessions#destroy'
end
resources :tasksadmins
resources :workers
root to: "workers#index"
end
You shouldn't return redirect_to in the after_sign_in_path_for. You should return url:
def after_sign_in_path_for(user)
if current_user.role_ids == [2]
return workers_url
else
return tasksadmins_url
end
end
I added to 'create' the next lines:
in the beginning, I wrote:
resource = warden.authenticate!(:scope => resource_name)
and then I wrote in the end of the 'create' function:
sign_in(resource_name, resource)
if current_user.role_ids == [2]
respond_with resource, :location => workers_path
else
respond_with resource, :location => tasksadmins_path
end
so my create looks so:
class UserSessionsController < Devise::SessionsController
include ApplicationHelper
def create
resource = warden.authenticate!(:scope => resource_name)
require "uri"
require "net/http"
## get the user id from the database
user_id = session['warden.user.user.key'][1][0];
## get the row by id
user = User.find(user_id)
# ============================
# Ensure that a user exists
# ============================
code, body = http_request(Net::HTTP::Put.new("/api/v1/users/external/#{user_id}"), email: user.email);
if code != 200
Rails.logger.error("Unable to register user #{current_user.email} at Licensario");
end
sign_in(resource_name, resource)
if current_user.role_ids == [2]
respond_with resource, :location => workers_path
else
respond_with resource, :location => tasksadmins_path
end
end
end
I faced this issue while using devise gem for my admin account management, but mine was on a production server.
AbstractController::DoubleRenderError (Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".):
The issue was that I wanted to sign_in into the admin dashboard, rather than entering the admin_dashboard URL into the browser, I put in the admin_sign_in URL in the browser, meanwhile, an admin account was already logged in. So when I tried to sign in it didn't work, because I can't sign-in 2 accounts at the same time to the admin dashboard.
Here's how I solved it:
Enter the URL for the admin dashboard into the browser, which signed me into the previous account
Log out from the account on the admin dashboard
And then sign-in to the admin dashboard using the account that I want.
That's all.
I hope this helps

wrong redirect after signing in

I have this controller.
class SessionsController < Devise::SessionsController
# GET /resource/sign_in
def new
self.resource = build_resource(nil, :unsafe => true)
clean_up_passwords(resource)
respond_with(resource, serialize_options(resource))
end
# POST /resource/sign_in
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in, :username => resource.username) if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_in_path_for(resource)
end
end
and this step-defenitions for cucumber:
Given /^a user "(.*?)" exists$/ do |user_name|
#user = User.create!(:username => user_name , :password => "tamara")
end
When /^he logs in$/ do
visit("/users/sign_in")
fill_in('Username', :with => "roelof")
fill_in('Password', :with => "tamara")
click_button('Sign in')
end
Then /^he should see "(.*?)"$/ do |message|
page.should have_content(message)
end
Everything works fine only after a successfull login I get redirect to the homepage and not to the login succceed page. So I don't see the flash message.
Roelof
Edit 1 : I checked the controller and resource_name and resource seems to have the right values.
the standard DeviseHelper for after_sign_in_path_for is the signed_in_root_path
# The scope root url to be used when he's signed in. By default, it first
# tries to find a resource_root_path, otherwise it uses the root_path.
You can check your routes and scope , and even debug by duplicating the Devise signed_in_root_path into your ApplicationController with a debugger line
By default, Devise's internal after_sign_in_path_for(resource) method first tries to find a valid {resource}_return_to key in the session, then it fallbacks to {resource}_root_path, otherwise it uses your root path route.
For instance, setting user_root_path would set direct path in the users scope after successful sign in (probably what you want):
# config/routes.rb
...
devise_for :users do
get 'users', :to => 'users#show', :as => :user_root
end
Or even:
# config/routes.rb
...
match 'user_root' => 'users#show'
Another way to override the redirect on successful login by overriding after_sign_in_path_for(resource):
# app/controllers/application_controller.rb
...
def after_sign_in_path_for(resource)
# Put some path, like:
current_user_path
end
Links for you to read:
How to: redirect to a specific page on successful sign in out
Method: Devise::Controllers::Helpers#after_sign_in_path_for
How To: Customize the redirect after a user edits their profile
How To: Change the redirect path after destroying a session i.e. signing out

Resources