Rails - Unknown attribute password
Asked Answered
H

1

1

I have been following Michael Hartl's Ruby on Rails tutorial book to try and add users to my application. Reading chapter 6, I have added what I believe to be the necessary fields for my user, specifically password and password confirmation via "has_secure_password".

I thought that adding "has_secure_password" to my user model would include the attributes "password" and "password_confirmation" provided I add a "password_digest" to the model. I have done that as the book instructed me to. However, when I run a test, Rails gives me the following error:

Error:
UserTest#test_should_be_valid:
ActiveModel::UnknownAttributeError: unknown attribute 'password' for User.
    test/models/user_test.rb:8:in `setup'

I tried this solution and it still gave me the same error, not recognizing the attributes "password" or "password_confirmation". I installed bcrypt using "gem install bcrypt" and included the following in my gem file:

gem 'bcrypt-ruby', :require => 'bcrypt'

I am using Rails 5 and it seems like "has_secure_password" is not supplying the password attributes that I need. Can anyone see what I missed or did wrong that caused "has_secure_password" to not work as intended? Thanks

User Model:

class User < ApplicationRecord

  has_many :activities

  class User < ActiveRecord::Base

    attr_accessor :name, :email, :password, :password_confirmation
    has_secure_password

    validates :first_name, presence: true, length: {minimum: 1}
    validates :last_name, presence: true, length: {minimum: 1}
    validates :email, presence: true, uniqueness: true, length: {minimum: 5}
    validates :username, presence: true, uniqueness: true, length: {minimum: 1}
    validates :password_digest, length: {minimum: 6}
    validates :password, :confirmation => true, length: {minimum: 4}
    validates :password_confirmation, presence: true

    #-----------------------New Stuff ---------------------------------------
    acts_as_authentic do |c|
      c.crypto_provider = Authlogic::CryptoProviders::Sha512
    end
    #------------------------------------------------------------------------

    #---------------Unsure if working--------------
    #validates_presence_of :password, :on => :create
    #validates_presence_of :email
    #validates_uniqueness_of :email
    #----------------------------------------------

    def self.authenticate(email, password)
      user = find_by_email(email)
      if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
        user
      else
        nil
      end
    end

    def encrypt_password
      if password.present?
        self.password_salt = BCrypt::Engine.generate_salt
        self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
      end
    end
  end
end

Apologies for the messy code on the model as I am still learning Rails.

User Controller:

class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      flash[:success] = 'Account created'
    else
      flash[:notice] ='ERROR: Account was not created'
      redirect_to 'users/new'
    end
  end

  def show
    @user = User.find(params[:id])
  end


  private
  def user_params
    params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)
  end
end

User Table:

 create_table "users", force: :cascade do |t|
    t.string   "first_name"
    t.string   "last_name"
    t.string   "username"
    t.string   "email"
    t.datetime "created_at",        null: false
    t.datetime "updated_at",        null: false
    t.string   "persistence_token"
    t.string   "password_digest"
    t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
  end

User Test:

require 'test_helper'

class UserTest < ActiveSupport::TestCase
  # test "the truth" do
  #   assert true
  # end
  def setup
    @user = User.new(first_name: 'test', last_name: 'tester', password: '1234',email: '[email protected]',
                     password: 'foobar', password_confirmation: 'foobar')
  end
  test 'should be valid' do
    assert @user.valid?
  end
end
Hypoacidity answered 9/4, 2017 at 2:16 Comment(1)
Why do you have a User class inside a User class ? Why did you declare an attr_accessor for password and password_confirmation ?Iberia
A
0

Update:

I have tested this out and it works. So hope will work for you as well :) Looks like MiniTest doesn't work well with BCrypt. I received the same error - undefined password, but later implemented my change and it went further well.


Original answer:

As of your founded solution it made me think that this makes no sence - adding getter and especially setter methods for :password and :password_confirmation. Because has_secure_password creates those virtually that runs through BCrypt. So doesn't it goes around crypting / encrypting? If so it is not safe. So only option left for testing I see take the BYcript into the testing suite. I think something like this might do the trck:

In User Test:

require 'bcrypt'

  def setup
    @user = User.new(first_name: 'test', last_name: 'tester', password: BCrypt::Password.create("my password") ,email: '[email protected]', password_confirmation: 'my password')
  end
  test 'should be valid' do
    assert @user.valid?
  end

Note that I removed duplicated password: 'foobar. Since with that particular test you are testing if User can be created, so shouldn't pass a different password or even duplicated attribute... Make another test for this (also checkout fixtures, they are great for creating test objects, as well as factories for more complicated cases).

And of course, remove the atr_accessor :password, :password_confirmation form your User model.

p.s. and please fix you code snippet for User class. Or is it really defined twice like this?:

class User < ApplicationRecord

  has_many :activities

  class User < ActiveRecord::Base
Atchison answered 9/4, 2017 at 8:13 Comment(1)
Thank you for the help. This worked and thank you for the advice on the two definition of Users. I'm still somewhat new at this so it was probably a solution I tried to fix another problem but forgot to remove it.Hypoacidity

© 2022 - 2024 — McMap. All rights reserved.