0

I'm attempting to configure a devise :confirmable account, in which a user selects his password once he confirms the account (this is an officially documented modification, the details of which can be found here).

The problem: Without the modification (in which I set the password when I first create the account), the confirmation works just fine. However, under the modification I get a 401 error (unauthorized). The log of which is below:

Started POST "/users/sign_in" for 192.168.1.8 at 2016-01-31 01:53:54 -0700
Processing by Users::SessionsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"O7mUtX/5i3Cw2sgAtn8+i4VAuytkHpcxZ0ZnKL6rmfmQsRj0MblP4OGY4K3dxqXQ7qjVMsqpYEIs7Oqkm9G3JA==", "user"=>{"email"=>"neanderslob@neanderslob.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "button"=>""}
  ^[[1m^[[36mUser Load (0.8ms)^[[0m  ^[[1mSELECT  "users".* FROM "users" WHERE "users"."email" = $1  ORDER BY "users"."id" ASC LIMIT 1^[[0m  [["email", "neanderslob@neanderslob.com"]]
  ^[[1m^[[35m (0.2ms)^[[0m  BEGIN
  ^[[1m^[[36m (0.1ms)^[[0m  ^[[1mCOMMIT^[[0m
Completed 401 Unauthorized in 70ms (ActiveRecord: 1.1ms)

Of course no password was entered, as this shouldn't be necessary.

Attached is my custom ConfirmationsController

class Users::ConfirmationsController < Devise::ConfirmationsController
  # Remove the first skip_before_filter (:require_no_authentication) if you
  # don't want to enable logged users to access the confirmation page.
   skip_before_filter :require_no_authentication
   skip_before_filter :authenticate_user!

  # GET /resource/confirmation/new
  def new
    super
  end

  # POST /resource/confirmation
  def create
    super
  end

  # GET /resource/confirmation?confirmation_token=abcdef
  def show
    with_unconfirmed_confirmable do
      if @confirmable.has_no_password?
        do_show
      else
        do_confirm
      end
    end
    unless @confirmable.errors.empty?
      self.resource = @confirmable
      render 'devise/confirmations/new' #Change this if you don't have the views on default path
    end
  end

  # PUT /resource/confirmation
  def update
    with_unconfirmed_confirmable do
      if @confirmable.has_no_password?
        @confirmable.attempt_set_password(params[:user])
        if @confirmable.valid? and @confirmable.password_match?
          do_confirm
        else
          do_show
          @confirmable.errors.clear #so that we wont render :new
        end
      else
        @confirmable.errors.add(:email, :password_already_set)
      end
    end

    if !@confirmable.errors.empty?
      self.resource = @confirmable
      render 'devise/confirmations/new' #Change this if you don't have the views on default path
    end
  end


  protected

  # The path used after resending confirmation instructions.
  def after_resending_confirmation_instructions_path_for(resource_name)
    super(resource_name)
  end

  # The path used after confirmation.
  def after_confirmation_path_for(resource_name, resource)
    super(resource_name, resource)
  end


  def with_unconfirmed_confirmable
    @confirmable = User.find_or_initialize_with_error_by(:confirmation_token, params[:confirmation_token])
    if !@confirmable.new_record?
      @confirmable.only_if_unconfirmed {yield}
    end
  end

  def do_show
    @confirmation_token = params[:confirmation_token]
    @requires_password = true
    self.resource = @confirmable
    render 'devise/confirmations/show' #Change this if you don't have the views on default path
  end

  def do_confirm
    @confirmable.confirm!
    set_flash_message :notice, :confirmed
    sign_in_and_redirect(resource_name, @confirmable)
  end
end

Some wild speculation: It also might be worth mentioning that this is all being done on my localhost. This means that the url it generates is from http://localhost:3000... where my app is built to respond to a custom domain. Before the customization, I was able to just change the confirmation link from localhost:3000 over to mydomain.com:3000 and everything was alright. However I don't know if this isn't allowed under my customization (honestly don't have a deep enough knowledge to say one way or another for sure).

Anyway, thanks for any ideas you might have!

Edit: My sessions controller (the relevant controller to the error message, as was pointed out to me) is as follows... note the commented out create method

class Users::SessionsController < Devise::SessionsController

  # GET /resource/sign_in
  def new
    super
  end

  # POST /resource/sign_in
  # def create
  #   super
  # end

  # DELETE /resource/sign_out
  def destroy
    super
  end
end
neanderslob
  • 2,633
  • 6
  • 40
  • 82
  • 1
    The log has nothing to do with the controller you posted. It's about your sessions controller. – sevenseacat Jan 31 '16 at 10:55
  • Is there any specific reason you REALLY need this? The problem is that the user will not be able to authenticate the user normally when doing the confirmation. I would reconsider. – max Jan 31 '16 at 11:12
  • @sevenseacat Well that was a useful observation (probably why they put it in there) :-P Turns out I had my `create` method commented out for some reason. Not sure why this hadn't thrown a wrench in any other sessions-related activities until now. Anyway, I'll put the sessions controller in my question; feel free to point out the obvious in an answer and I'd be happy to give you credit. – neanderslob Jan 31 '16 at 11:22
  • @max Thanks for your response; this method of user management is necessary, as I need for user creation to be exclusively in the hands of a select group of admins and then for users to be alerted that they've had an account created for them. I don't entirely understand your concern; if you have a moment, could you restate the second sentence in your comment? – neanderslob Jan 31 '16 at 11:32
  • Basically the way devise confirmations works is that the user is created normally but is not flagged as confirmed - the user then performs the confirmation step where he/she can be authenticated via email/pw just like any other user. However if the user does not have a PW you cannot use the normal Warden strategy. Your use case is so different than what devise confirmable is meant to do that you would probably be better off writing something from scratch rather than poking holes in it everywhere. – max Jan 31 '16 at 11:45

0 Answers0