0

I've tried looking at previous questions and answers regarding this error, but the solutions didn't seem to work for me. The error is thrown on the line:

if customer && customer.authenticate(params[:session][:password_digest])

I am able to Sign Up a user (under a company) and sign up a company, but I get this BCrypt error whenever I try to log a user in. I only started using the has_secure_password stuff etc once my user model and company model etc. were in place, I just realised later that it was silly to not protect passwords. Even if I create a new user now, I still get this error logging on.

I think this might be due to my relationships of my Users? (maybe completely not, I am very new to Ruby!) My users belong to a company (many to one), and when they sign up they choose a company from a list in order to be listed under it in the database. Here is my code relating to this error:

class SessionsController < ApplicationController

  def new

  end

  def create
    customer = Customer.find_by_email(params[:session][:email])
    if customer && customer.authenticate(params[:session][:password_digest])
      log_in customer #see sessions helper
      remember customer #see sessions helper
      redirect_to '/main'
    else
      redirect_to '/login'
    end
  end

  def destroy
    #session[:user_id] = nil
    forget(current_customer)
    session.delete(:customer_id)
    @current_customer = nil
    redirect_to '/'
  end
end



class CreateCustomers < ActiveRecord::Migration
  def change
    create_table :customers do |t|
      t.timestamps
      t.references :business, foreign_key: true

      t.timestamps
      t.string :first_name
      t.string :last_name

      t.string :email
      t.string :password_digest
      t.string :remember_digest
      t.string :role
    end
  end
end


class CustomersController < ApplicationController
  def new
    @customer = Customer.new
    @businesses = Business.all
  end

  def create
    @customer = Customer.create(customer_params)
    @customer.save!
    session[:customer_id] = @customer.id
    redirect_to '/'
  rescue ActiveRecord::RecordInvalid => ex
    render action: 'new', alert: ex.message
  end

  private
  def customer_params
    params.require(:customer).permit(:first_name, :last_name, :business_no, :email, :password_digest, :business_id) #replace company with company ID
  end
end

Please help me, I'm tearing my hair out :(

Sean
  • 333
  • 4
  • 9
Sarahshuffle
  • 182
  • 2
  • 11
  • 2
    May or may not be relevant but you should be calling `authenticate` with the plain text password rather than the `password_digest`. So `if customer && customer.authenticate(params[:session][:password])`. [Source](http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html) – Sean Nov 25 '15 at 20:39
  • Does it matter if i've only defined the password_digest in the user migrate? If it doesn't, do I do that by changing the log in form password fill in symbol to :password rather than :password_digest? – Sarahshuffle Nov 25 '15 at 21:25

1 Answers1

4

The error you're getting probably means that the password_digest stored for that user is invalid for some reason (empty perhaps). Enter a rails console: rails console and execute the following:

u = User.find_by(email: "your_user_email")
puts u.password_digest

and see what the output is.

(also as mentioned in a comment on your question, you should use the plain text password when you use the authenticate method)

Update

You shouldn't use the password_digest attribute directly, instead there are two attributes you should be using: password and password_confirmation (these attributes become available to you automatically when you use has_secure_password, so you don't need to define them).

So in your controller, instead of this:

params.require(:customer).permit(:first_name, :last_name, :business_no, :email, :password_digest, :business_id) #replace company with company ID

You should have:

params.require(:customer).permit(:first_name, :last_name, :business_no, :email, :password, :password_confirmation :business_id) #replace company with company ID

and edit your form accordingly to provide inputs for password and password_confirmation.

Now when you create your object using these params, it will automatically assign the password digest into password_digest by encrypting the clear text contained in password and password_confirmation.

Amr Noman
  • 2,597
  • 13
  • 24
  • 1
    ok, I am very confused. Could you explain to me why this is happening? c = Customer.find_by(email: "sarahcraig1994@yahoo.com") Customer Load (1.0ms) SELECT "customers".* FROM "customers" WHERE "customers"."email" = 'sarahcraig1994@yahoo.com' LIMIT 1 # >> puts c.password_digest password nil – Sarahshuffle Nov 25 '15 at 21:31
  • why is it returning both "password" (the password I signed up with) and 'nil'? – Sarahshuffle Nov 25 '15 at 21:32
  • Don't worry about the `nil`, the `puts` method always returns `nil`. – Amr Noman Nov 25 '15 at 21:45
  • 1
    Now, your problem is that your `password_digest` equals `password` and that's not a valid password hash, this is the reason you get the error. `Bcrypt` expects `password_digest` to be a valid digest, not a clear text. In other words the value for `password_digest` is supposed to be a long encrypted string. How are you storing the password for you model? – Amr Noman Nov 25 '15 at 21:48
  • glad I could help, please mark the answer as correct. – Amr Noman Nov 25 '15 at 22:07