ranieri
ranieri

Reputation: 2078

Custom user authentication on Rails 4

I'm trying to learn and use my own user model and authentication with Ruby on Rails 4.0, but most tutorials (if not all) seem to be outdated with this recent update. No method described on any of them works. I'm absolutely clueless, this is my User model:

class User
  include Mongoid::Document
  field :login, type: String
  field :hash, type: String
  field :salt, type: String
  field :email, type: String
  field :name, type: String

  before_save :hash_password

  validate :login, presence: true, uniqueness: true, length: { in: 4..24 }
  validate :password, presence: true, confirmation: true, length: { in: 8..32 }
  validate :email, presence: true
  validate :name, presence: true

  def hash_password
    if password.present?
      self.salt = BCrypt::Engine.generate_salt
      self.hash = BCrypt::Engine.hash_secret(password, salt)
    end
  end
end

And the controller:

class UsersController < ApplicationController
  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user
    else
      render 'new'
    end
  end

  def new
    @user = User.new
  end

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

I then get an UnknownAttribute error when I save the user. What am I missing? What fields are wrong?

Upvotes: 0

Views: 1844

Answers (3)

ranieri
ranieri

Reputation: 2078

I managed to make it work. I didn't figure out what was the matter with the "unknown attribute" error, but I changed the model to use the method has_secure_password, which automagically takes my :password and :password_confirmed parameters, bcrypts and save to :password_digest field.

class User
  include Mongoid::Document
  include ActiveModel::SecurePassword # important, imports has_secure_password
  field :login, type: String
  field :password_digest, type: String
  has_secure_password
  field :email, type: String
  field :name, type: String

  validate :login, presence: true, uniqueness: true, length: { in: 4..24 }
  validate :password, presence: true, confirmation: true, length: { in: 8..32 }
  validate :email, presence: true, uniqueness: true
  validate :name, presence: true
end

This done, I got the following error:

can't activate bcrypt-ruby (~> 3.0.0), already activated bcrypt-ruby-3.1.2. Make sure all dependencies are added to Gemfile.

Even though bcrypt was correctly added to my Gemfile, apparently has_secure_password needs specifically version 3.0.x of the gem, so I forced it:

gem 'bcrypt-ruby', '~> 3.0.0'

This downloaded the version 3.0.1 (not 3.0.0) which worked as expected. I hope they fix this version incompatibility soon.

Thanks for all the answers. This project will be available open source when I finish :)

Upvotes: 1

Mandeep
Mandeep

Reputation: 9173

You can follow rail casts episode. I know its a bit old but i also used it a couple of months ago and for the rails 4 you can simply "permit" the attributes rather than using "attr_accessible" as rails 4 doesn't support attr_accessible.

Upvotes: 1

Austin Lin
Austin Lin

Reputation: 2564

You need to add:

attr_accessor :password

Right now you are trying to use the password attribute but rails doesn't know anything about it. attr_accessor allows you to use the password attribute locally, but will not persist it to the database (which is good).

Upvotes: 1

Related Questions