38

I have my rails application and I am running into a major issue with devise. I have a controller:

class Users::SessionsController < Devise::SessionsController
  prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
  include Devise::Controllers::InternalHelpers

def new
    clean_up_passwords(build_resource)

    respond_to do |format|
      format.html { render :layout => "sessions" }
      format.mobile
    end
  end


    # POST /resource/sign_in
    def create
      resource = User.find_by_email(params[:user][:email])  
      resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
      set_flash_message :notice, :signed_in
      sign_in_and_redirect(resource_name, resource)
    end

end

The problem is it never logs the user in, it always stops at this line

resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")

I even put tons of loggers in the actual gem files to see if I could see anything off but nothing and I really have no idea how to fix this. If I comment this line out then the user gets logged in but fails if the email is not in the db and works for any password (which is definitely not the right solution)

How do I fix this?

UPDATE

this works but seems very hackish

# POST /resource/sign_in
def create
  resource = User.find_by_email(params[:user][:email])

  redirect_to(new_user_session_path, :notice => 'Invalid Email Address or Password. Password is case sensitive.') and return if resource.encrypted_password.blank?      
  bcrypt   = BCrypt::Password.new(resource.encrypted_password)
  password = BCrypt::Engine.hash_secret("#{params[:user][:password]}#{resource.class.pepper}", bcrypt.salt)
  valid = Devise.secure_compare(password, resource.encrypted_password)
 # resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
  if valid
    set_flash_message :notice, :signed_in
    sign_in_and_redirect(resource_name, resource)
  else
    redirect_to(new_user_session_path, :notice => 'Invalid Email Address or Password. Password is case sensitive.') and return    
  end

end
Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
Matt Elhotiby
  • 43,028
  • 85
  • 218
  • 321

5 Answers5

86

If you want to sign in a user, use the sign_in helper inside your controller's action:

sign_in(:user, user)
Ryan Bigg
  • 106,965
  • 23
  • 235
  • 261
  • 2
    this logs them in regardless even if the password is wrong or not – Matt Elhotiby Feb 18 '12 at 17:21
  • 35
    Check `user.valid_password?(params[:password])` first, then. – Ryan Bigg Feb 20 '12 at 13:22
  • I tried exactly like this but got wrong number of arguments (2 for 0). any idea? – ishwr Oct 03 '13 at 10:17
  • @takodil Maybe that method is being defined by something else. Open a new SO question and include your code. Along with that information, show us the output of `method(:sign_in).source_location` in this new question as well. – Ryan Bigg Oct 06 '13 at 22:36
  • @RyanBigg Thank you for replying. I made a new SO question. http://stackoverflow.com/questions/19172935/devise-sign-in-from-a-controller Can you tell me where should I put method(:sign_in).source_location ? thanks – ishwr Oct 07 '13 at 02:36
  • @Trace A valid use case for signing the user in without validating the password is during a customized registration process, for example. – Caleb Jul 20 '14 at 12:57
1
  resource = warden.authenticate!(:scope => resource_name)
   sign_in(resource_name, resource)
Mike
  • 1,626
  • 1
  • 12
  • 14
0

I found this post useful for setting up a login for request specs. https://makandracards.com/makandra/37161-rspec-devise-how-to-sign-in-users-in-request-specs

module DeviseRequestSpecHelpers

  include Warden::Test::Helpers

  def sign_in(resource_or_scope, resource = nil)
    resource ||= resource_or_scope
    scope = Devise::Mapping.find_scope!(resource_or_scope)
    login_as(resource, scope: scope)
  end

  def sign_out(resource_or_scope)
    scope = Devise::Mapping.find_scope!(resource_or_scope)
    logout(scope)
  end

end

Include it in your spec_helper

RSpec.configure do |config|
  config.include DeviseRequestSpecHelpers, type: :request
end

And sign in as needed

sign_in create(:user, name: 'John Doe')

Clam
  • 935
  • 1
  • 12
  • 24
0

Here is how standard create actions works:

  # POST /resource/sign_in
  def create
    self.resource = warden.authenticate!(auth_options)
    set_flash_message!(:notice, :signed_in)
    sign_in(resource_name, resource)
    yield resource if block_given?
    respond_with resource, location: after_sign_in_path_for(resource)
  end

https://github.com/plataformatec/devise/blob/master/app/controllers/devise/sessions_controller.rb#L18

Artur INTECH
  • 6,024
  • 2
  • 37
  • 34
0

Checkout this gem https://github.com/ankane/pretender

You can do something like:

class ApplicationController < ActionController::Base
  impersonates :user
end

besides that the author says is fully customizable: https://github.com/ankane/pretender#configuration

impersonates :user,
             method: :current_user,
             with: ->(id) { User.find_by(id: id) }
Nick_K
  • 541
  • 6
  • 22