How to sign in a user using Devise from a Rails console?
Asked Answered
L

5

56

After loading the Rails console, how should I sign in a user?

Devise provides a test helper which can be used in tests and I've tried to use in console:

>> include Devise::TestHelpers
>> helper.sign_in(User.first)

But I get:

NoMethodError: undefined method `env' for nil:NilClass

Anyway, I would like to use the real devise helper and not this test helper. Is there any way to achieve this?

Lettie answered 8/2, 2011 at 2:39 Comment(0)
N
88

Here's one way I was able to do it:

>> ApplicationController.allow_forgery_protection = false
>> app.post('/sign_in', {"user"=>{"login"=>"login", "password"=>"password"}})

Then you can do:

 >> app.get '/some_other_path_that_only_works_if_logged_in'
 >> pp app.response.body
Newsmonger answered 8/2, 2011 at 3:44 Comment(4)
With modern Devise you will have to use email instead of login: app.post('/sign_in', {"user"=>{"email"=>"login", "password"=>"password"}})Transversal
How is "app" initialized in this context?Fourpence
app is initialized when you start the console. You don't have to do anything extra.Newsmonger
I had to use app.post('/users/sign_in', {params: {"email"=>"[FILTERED]", "password"=>"[FILTERED]"}}) but otherwise works great ty! That bit about the forgery_protection would have held me up all day!Lickerish
G
16

Here is another example which uses the csrf token, authenticates the user, and makes a POST/GET request.

# get csrf token
app.get  '/users/sign_in'
csrf_token = app.session[:_csrf_token]

# log in
app.post('/users/sign_in', {"authenticity_token"=>csrf_token, "user"=>{"email"=>"foo", "password"=>"bar"}})

# get new csrf token, as auth user
app.get ''
csrf_token = app.session[:_csrf_token]

# make a POST request
app.post '/some_request.json', {"some_value"=>"wee", "authenticity_token"=>csrf_token}

# make a GET request
app.get '/some_other_request.json'
Glairy answered 20/5, 2015 at 13:30 Comment(3)
an old answer, but still. This was the correct one for me!Fratricide
The syntax for passing params to app.post has changed to app.post '/users/sign_in', params: {"authenticity_token"=>csrf_token, ....Snakebite
For Rails 6, you may need to add config.hosts.clear to your development.rb file — as explained hereJaclynjaco
S
5

Important to note that since Rails 5, the params parsing has been changed to take only one argument and params (instead of params being a second argument.

ActionDispatch::ParamsParser is deprecated and was removed from the middleware stack. To configure the parameter parsers use ActionDispatch::Request.parameter_parsers=

So these earlier examples will no longer work in modern Rails without patching your middleware. To make them work, simply include the arguments in the POST params like:

app.post('/users/sign_in', {"user"=>{"email"=>"[email protected]", "password"=>"mycoolpassword"}}) <-- No longer valid

app.post('/users/sign_in', params: {"user"=>{"email"=>"[email protected]", "password"=>"mycoolpassword"}}) <-- valid

Synchroscope answered 30/4, 2020 at 11:54 Comment(0)
N
3

You can add an action inside one of your controller, and use the technique explained here.

class MyController < ApplicationController
  # POST /my_controller/become {'email': '[email protected]'}
  def become
    raise 'not in development environment' unless Rails.env == 'development'
    sign_in User.find_by_email(params[:email])
  end
end
Needful answered 17/6, 2015 at 13:54 Comment(3)
This doesn't really answer the question, since the question is about signing iin from the console, and not signing in as another user from the web app.Swagman
But its still helpful, you can call this method from console also. I came searching through google here and yes above answers are nice and working but this one is helpful for me too. So don't just keep giving negative votes to anyone like this.Hebel
is there any way to use sign_in on the console? since i need to generate a token access but this will happen after the loginChavira
K
0

There is a better way to do that. Add this code to the config/application.rb

# config/pplication.rb

  class Application < Rails::Application
    # ...
    console do
      class ActionDispatch::Integration::Session
        def host; 'localhost'; end
      end

      class ::BackdoorController < Devise::SessionsController
        def comeonin
          sign_in $current_user
          render json: {}
        end
      end
      Rails.application.routes.disable_clear_and_finalize = true
      Rails.application.routes.draw do
        devise_scope(:user) { get '/backdoor', to: "backdoor#comeonin" }
      end
    end
    # ...
  end

Now you can log in on behalf of any user:

$current_user = User.last
app.get '/backdoor' # sign in
app.get '/profile' # any other request

In the case of HTTPS, one may need to use the full hostname:

app.get 'https://localhost/backdoor'
Klecka answered 13/5, 2021 at 14:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.