How to sign_in user after devise email confirmation in Rails - ruby-on-rails

I am trying from last 7 hours to auto signin the user after email confirmation but when I click the confirmation link then it says "Your email address has been successfully confirmed." but not sign in the user. I have written this code in my confirmations controller and route
devise_for :users, controllers: {confirmations: 'users/confirmations'}
class ConfirmationsController < Devise::ConfirmationsController
#private
def after_confirmation_path_for(resource_name, resource)
sign_in(resource)
render plain: "here"
redirect_to "/admins/view_account", notice: "User deleted."
end
end
Any help would be highly appreciated Thanks.

Notice that automatically sign in after e-mail confirmation used to be Devise's default behavior and was then changed (after 3.1) due to security measures as you can see more here and here.
If you still want to do it, depending on the Devise's version make sure to set the line below on the config/initializers/devise.rb file within your project:
config.allow_insecure_sign_in_after_confirmation=true
If you are using latest Devise version, you may have to instead of that, extend the default controller with this code on app/controllers/users/confirmations_controller.rb as a replacement of what you have mentioned above for controller code (please mind the namespaces and path mentioned):
class Users::ConfirmationsController < Devise::ConfirmationsController
def show
super do |resource|
sign_in(resource) if resource.errors.empty?
end
end
end
And make sure the code you pasted in the beginning of the question belongs in config/routes.rb:
devise_for :users, controllers: { confirmations: 'users/confirmations' }
Hope it helps!

I have solved it myself.
routes should be like this
devise_for :users, controllers: {confirmations: 'confirmations'} do
#put "confirm_user", to: "confirmations#confirm_user"
get "confirmation", to: "confirmations#after_confirmation_path_for"
end
Controller is like this
class ConfirmationsController < Devise::ConfirmationsController
#private
def after_confirmation_path_for(resource_name, resource)
sign_in(resource)
#render plain: "here"
#redirect_to "/admins/"
end
def show
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
if resource.errors.empty?
set_flash_message(:notice, :confirmed) if is_flashing_format?
sign_in(resource) # <= THIS LINE ADDED
redirect_to "/your path/"
else
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render :new }
end
end
end

Related

Devise crud + namespaces: Pro level :)

I have Devise Admin & Devise User;
I want to use namespaces;
What I want to achieve:
only devise admin can create devise user
registerable for user is not deleted so that he can edit only page
user can see only current_user/show page
What I have
routes:
Rails.application.routes.draw do root :to => 'dashboard#index'
devise_for :users, controllers: { registrations: 'user_registrations' }
devise_for :admins, controllers: { registrations: 'admin_registrations' }
get 'dashboard/index'
namespace :admin do
root 'dashboard#index'
resources :users
end
user_registration_controller:
class UserRegistrationsController < Devise::RegistrationsController
end
users_controller:
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def edit
end
def create
#user = User.new(user_params)
respond_to do |format|
if #guest.save
format.html { redirect_to users_path }
else
format.html { render :new }
end
end
end
def update
respond_to do |format|
if #user.update(user_params)
format.html { redirect_to #user }
else
format.html { render :edit }
end
end
end
def destroy
user = User.find(params[:id])
user.destroy
redirect_to users_path
end
private
def set_user
#user = User.find(params[:id])
end
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
+ I have user views as they would be in a normal scaffold.
=> With this setup, anyone can create a user
Any ideas how to solve the questions on top?..
Don't use separate user classes with Devise, use roles instead. Devise is only really made to authenticate a single class, while you can hack it into using two classes its a mess. You have to override all the logic of serializing/desearializing users from the session among other things so that devise knows if it should load the Admin or User class.
Its also a bad solution since you are push down a authorization problem into the authentication layer. Devise's job is to verify that the user is who she/he claims to be, which is no small feat. Authorization, on the other hand is rules about what a user can do. "Only admins can create users" is a clear cut authorization rule.
The simplest possible role based authorization would be something like this:
class AddRoleToUser < ActiveRecord::Migration
def change
add_column :users, :role, :integer, default: 0
add_index :users, :role
end
end
class User
# ...
enum role: [:visitor, :admin]
end
We use an enum which is a single bitmask column to store the users role. Declaring it as an enum column also gives us a few methods for free:
user.visitor?
user.admin?
user.admin!
So lets create a basic authorization check:
def create
unless current_user.admin?
redirect_to root_path, status: 401, error: 'You are not authorized to perform this action' and return
end
# ...
end
But we don't want to repeat that every time we want to authorize, so lets clean it up:
class AuthorizationError < StandardError; end
class ApplicationController
rescue_from AuthorizationError, with: :deny_access!
private
def authorize_admin!
raise AuthorizationError, unless current_user.admin?
end
def deny_access!
redirect_to root_path,
status: 401,
error: 'You are not authorized to perform this action'
end
end
So then we can setup the controller with a filter to check the authorization before the action is performed:
class UsersController < ApplicationController
before_action :authorize_admin!, except: [:show]
# ...
end
However instead of reinventing the wheel you might want to have a look at Pundit or CanCanCan which are solid authorization libraries with great communities. You also might want to look at Rolify.

How can I redirect a user to a specific page when registration fails?

I have a Rails app which uses Devise for user sign up / authentication. Both the sign up form and the login form are at the root of my domain.
When user registration fails (for example because they enter an email address which is already taken), by default Devise redirects to /users.
How can I change that? I would like the user to be directed to /
I have implemented this successfully for a failed login attempt, with the following code:
class CustomFailure < Devise::FailureApp
def redirect_url
"/"
end
def respond
if http_auth?
http_auth
else
redirect
end
end
end
and:
config.warden do |manager|
manager.failure_app = CustomFailure
end
As detailed on the project's homepage.
Is there any way to extend / alter this so that failed registrations also redirect to the root of my domain?
I'm using Ruby 2.2.0, Rails 4.2.0 and Devise 3.4.1.
You will probably need to subclass Devise::RegistrationsController and override the create action. Just copy over the create method from here and modify the redirect on failure to save.
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
build_resource
if resource.save
set_flash_message :notice, :inactive_signed_up, :reason => inactive_reason(resource) if is_navigational_format?
expire_session_data_after_sign_in!
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
#end
else
clean_up_passwords(resource)
respond_with_navigational(resource) { render_with_scope :new }
end
end
end
# The path used after sign up for inactive accounts. You need to overwrite
# this method in your own RegistrationsController.
def after_inactive_sign_up_path_for(resource)
new_user_session_path
end
Change your routes to tell Devise to use your controller:
# config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
I believe you can take a look at this question. You can override Devise RegistrationsController and add your redirect_to method to an else when User is not saved.
For example:
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
if #user.save?
#something
else
redirect_to your_path, error: 'Registration failed'
end

RoR : Are devise controllers generated automatically or should we write on our own?

I am new to ruby on rails. I am trying to use devise gem for authentication. i am going through the tutorials in github. I have created devise views using rails generate devise:views. But i dont find any controllers. Do i need to create on my own or is there any command to generate controllers for it?
Plz help
Devise already creates the required controllers for you behind the scenes. Few of these controllers are: RegistrationController, SessionController.
To customize or override any controller, say RegistrationController; you can do following (snippet from my one application):
class RegistrationsController < Devise::RegistrationsController
before_filter :admin_user, :only => [:destroy]
def new
super
end
def create
if simple_captcha_valid? #verifying user registration by captcha
super
else
build_resource
clean_up_passwords(resource)
flash.now[:alert] = "There was an error with the captcha code below. Please re-enter the code."
render :new
end
end
def update
# required for settings form to submit when password is left blank
if params[:user][:password].blank?
params[:user].delete("password")
params[:user].delete("password_confirmation")
end
#user = User.find(current_user.id)
if #user.update_attributes(params[:user])
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
sign_in #user, :bypass => true
redirect_to after_update_path_for(#user)
else
render "edit"
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to rooth_path
end
end
For more you can follow: https://github.com/plataformatec/devise#configuring-controllers

overriding password controller in devise not working

I have problems when overriding passwords controller in devise. I do not want to sign in the user after password is changed so i thought of overriding the password controller and i tried as follows and got an error. I could not identify what the problem is, so please help me. The following is the passwords_controller.rb
class PasswordsController < Devise::PasswordsController
prepend_before_filter :require_no_authentication
# Render the #edit only if coming from a reset password email link
append_before_filter :assert_reset_token_passed, :only => :edit
def new
super
end
def create
super
end
def edit
self.resource = resource_class.new
resource.reset_password_token = params[:reset_password_token]
end
def update
self.resource = resource_class.reset_password_by_token(resource_params)
if resource.errors.empty?
flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
set_flash_message(:notice, "New password has been saved")
redirect_to new_user_session_path
else
respond_with resource
end
end
protected
# The path used after sending reset password instructions
def after_sending_reset_password_instructions_path_for(resource_name)
new_session_path(resource_name)
end
# Check if a reset_password_token is provided in the request
def assert_reset_token_passed
if params[:reset_password_token].blank?
set_flash_message(:error, :no_token)
redirect_to new_session_path(resource_name)
end
end
# Check if proper Lockable module methods are present & unlock strategy
# allows to unlock resource on password reset
def unlockable?(resource)
resource.respond_to?(:unlock_access!) &&
resource.respond_to?(:unlock_strategy_enabled?) &&
resource.unlock_strategy_enabled?(:email)
end
end
and my routes is
devise_for :users, :controllers => { :passwords => 'passwords' }
and the error i get is
NameError in PasswordsController#update
undefined local variable or method `resource_params' for #<PasswordsController:0x000001008231c8>
Your 'resource_params' is undefined. May be you should get it as a parameter :
def update
self.resource = resource_class.reset_password_by_token(params[:resource_params])
....
Finally it works. I am using devise version 1.5.3 and it does not provide resource_params method so i copied the following from devise version 1.5.3 and it works.
self.resource =
resource_class.reset_password_by_token(params[resource_name])

How do I resolve "Invitation token can't be blank" for DeviseInvitable

I am using strong_parameters and devise_invitable in my rails application. If I leave it as it is the "Forbidden Attribute" run time error is what I get. So I did the following:
Created a new controller using rails g controller users/invitations
Added :invitations => "users/invitations" to devise_for
Populated users/invitations.rb like so:
class Users::InvitationsController < Devise::InvitationsController
def update
self.resource = resource_class.accept_invitation!(allowed_params)
if resource.errors.empty?
set_flash_message :notice, :updated
sign_in(resource_name, resource)
respond_with resource, :location => after_accept_path_for(resource)
else
respond_with_navigational(resource){ render :edit }
end
end
private
def allowed_params
params.permit(:utf8,:authenticity_token,:invitation_token, :_method,
{user: [:invitation_token,:password,:password_confirmation]}, :commit,
:action,:controller)
end
end
However, when I do that I get the error "Invitation token can't be blank". I've checked the values of allowed_params, using puts and it appears that it is there. Yet, I still get the error.
I found my problem and answered it on the wiki.

Resources