How to skip has_secure_password validations
I decided to do my own custom authentication. The following solution will validate passwords but only when they are being set. This allows admins to create users without adding a password.
class User < ActiveRecord::Base
include BCrypt
attr_accessor :password, :password_confirmation
validates :password, length: (6..32), confirmation: true, if: :setting_password?
def password=(password)
@password = password
self.password_hash = Password.create(password)
end
def authenticate(password)
password.present? && password_hash.present? && Password.new(password_hash) == password
end
private
def setting_password?
password || password_confirmation
end
end
If someone posts an answer that allows me to still use the has_secure_password
method, I'll accept it instead.
How to disable password/confirmation validations when using has_secure_password in Rails 3.2?
You could add a conditional :if
to both validators:
Option 1:
validates :password , length: { minimum: 6 }, :if => :validate_password?
validates :password_confirmation, presence: true , :if => :validate_password?
def validate_password?
password.present? || password_confirmation.present?
end
Option 2:
Or use a method for validation, moving the validation checks into the method instead of as separate validates
calls:
validate :check_password, :on => :update
def check_password
return unless password.present? || password_confirmation.present?
..validations for both attributes here..
..check presence, length etc. as required and add to the errors variable as necessary..
end
How to skip validation on regeneration of secure token
You can do
def generate_password_reset_token
self.reset_password_token = generate_token
self.reset_password_sent_at = Time.now
save!
end
def generate_token
SecureRandom.base58(5)
end
Can I conditionally remove the has_secure_password requirement when creating a second user?
We had the same issue in our app. Our solution was to generate a password for the users when new users are created using this: before_validation :set_random_password, on: :create
Then the users can select their own password when they activate their account. This way we do not have to do anything custom with the validations which might compromise security for active users.
More of the code (as requested)
def set_random_password
password = SecureRandom.base64(100)
end
Then we use perishable tokens for finding the user and allowing them to update their password. A perishable token is some secure string that updates every time the user is updated in the database. We use the same pattern for "forgot password emails".
We build a link looking like /users/activate?token=#{user.token}
and send that in a email.
Then in the controller
def activate_user_form
@user = User.find_by(token: params[:token])
render :select_password_form
end
def activate_user
@user = User.find_by(token: params[:token])
@user.password = params[:password]
@user.active = true
if @user.save
...
end
Or something along those lines.
Rails has_secure_password - either no blankness validation or two validation errors
You can pass an option to has_secure_password
to skip its built-in validations and use your own:
has_secure_password(validations: false)
https://github.com/rails/rails/blob/869a90512f36b04914d73cbf58317d953caea7c5/activemodel/lib/active_model/secure_password.rb#L66
Validating presence of has_secure_password only when password is in params
To answer your question, It seems best to have change_password
and reset_password
controller actions and do your validations in there.
First, have your model validate password only on create or when it's already entered as such:
validates :password, :presence => true,
:length => { minimum: 6 },
:if => lambda{ new_record? || !password.nil? }
Then for your new controller actions, something along the lines of:
class UsersController < ApplicationController
def change_password
...
if params[:user][:password].present?
@user.update_attributes(params[:user])
redirect_to root_path, notice: "Success!"
else
flash.now.alert "Please enter password!"
render "change_password"
end
end
end
Do the same for reset_password and you should be golden!
Related Topics
How to Solve Insecure World Writable Dir /Usr in Path,Mode 040777 Warning on Ruby
Before/After Suite When Using Ruby Minitest
How to Test 'Rand()' with Rspec
Show Full Path Name of the Ruby File When It Get Loaded
Rails Active Admin CSS Conflicting with Twitter Bootstrap CSS
Bundle Install Issue with Libv8 and Rails
Why Is Rails Outputting My Array
Replace Words in a String - Ruby
Format the Date Using Ruby on Rails
How to Compile Ruby to Byte Code as with Python
Difference Between Integer(Value) and Value.To_I
How to Change Column Type in Heroku
How to Insert a String into a Textfile
What's the Point of Freezing Your Rails Version/Gems
How to Use Controller Specific Stylesheets in Rails 3.2.1