Rails: How to validate password from input if there is not password field in database

ruby-on-rails

Solution

You're validating the user's `password` attribute but you never assign it a value in the first place. At the least, you need to add this to your controller code:

@student.password = params[:student][:password]
@student.password_confirmation = params[:student][:password_confirmation]

However, the more concise way is to use mass-assignment - get rid of all the @student.xxx = yyy and replace it with this:

@student = Studen.new(params[:student])

Then, move your password hashing method into the model and trigger it automatically before each save if the password attribute is present:

class User < ActiveRecord::Base
  # ...
  before_save :hash_password, :if => proc{ |u| !u.password.blank? }
  # ....

  protected

  def hash_password
    self.salt = BCrypt::Engine.generate_salt
    self.password_hash = BCrypt::Engine.hash_secret(password, salt)
  end
end

This way you don't have to do anything in the controller but this:

def create
  @student = Student.new(params[:student])
  if @student.save
    redirect_to controller: 'singups', action: 'index'
  else
    render 'sing_up'
  end
end

and have all other logic in your model, where it belongs.

EDIT: In order for mass assignment to work with the latest versions of Rails 3, you'll need to make the attributes you want to assign like that `attr_accessible`, like this:

class Student < ActiveRecord::Base
  # ...
  attr_accessible :first_name, :last_name, :email, :password # but NOT the hash or salt!!

end

Problem

I have table with fields: `email`, `password_hash` and `salt`. On user registration, I want to validate password and password confirmation, but I always get error that says `can't be blank` for password input. This is my model: ``` attr_accessor :password validates :password, :presence => true, :confirmation => true, :length => { :within => 6..40 } ``` I guest I can't validate field that is not it the database, but how to make validation on password that user enters? I don't have password field in database because I encypt that `password` input I get and then I store it in db `password_hash` field. EDIT : This is database table: ``` class CreateStudents < ActiveRecord::Migration def change create_table :students do |t| t.string :first_name t.string :last_name t.string :email t.string :password_hash t.string :salt t.boolean :activated t.timestamps end end end ``` This is the view for registration: ``` <%= form_for @student, url: {action: 'create'} do |form| %> <p style="font-size:smaller; color:red"> <% @student.errors.messages.each do |att, msg| %> <%= msg[0] %><br> <% end %> <p> <%= form.label :first_name %><br> <%= form.text_field :first_name %> <p> <%= form.label :last_name %><br> <%= form.text_field :last_name %> <p> <%= form.label :email %><br> <%= form.text_field :email %> <p> <%= form.label :password %><br> <%= form.password_field :password %> <p> <%= form.label :password_confirmation %><br> <%= form.password_field :password_confirmation %> <p> <%= form.submit %> <% end %> ``` This is the controller: ``` def sing_up @student = Student.new render 'sing_up' end def create @student = Student.new @student.first_name = params[:student][:first_name] @student.last_name = params[:student][:last_name] @student.email = params[:student][:email] @student.salt = BCrypt::Engine.generate_salt @student.password_hash = BCrypt::Engine.hash_secret(params[:student][:password], @student.salt) if @student.save redirect_to controller: 'singups', action: 'index' else render 'sing_up' end end ``` and finnaly, this is model ``` class Student < ActiveRecord::Base attr_accessor :password validates :first_name, :length => { minimum: 3, message: "first_name" } validates :last_name, :length => { minimum: 3, message: "last_name" } validates :email, :presence => { message: 'email' }, :format => { with: /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/ , message: 'email format' }, :uniqueness => { message: 'uniqueness?' } validates :password, :confirmation => { message: 'password' }, :length => { minimum: 6, message: 'password length' } end ``` Every time user enters password it fails on first validation `:confirmation => { message: 'password' }`, no matter what the password was. If I remove `validates :password` part, everything works fine, but password that user enters is not validated.

Original source