0

I'm relatively new to Rails (using Rails 4), and am having a problem with validation for my user model. Even when the form is fully filled in with both the passwords, when I submit the code two errors print out:

{:password=>["can't be blank"], :password_confirmation=>["doesn't match Password"]}

I would like the user to be saved into the database, but these validation errors are preventing that from happening. What I would like to know is what I need to change in order to get rid of these errors.

I am printing out the params object and it looks like this (the authenticity token is omitted here):

params: {"utf8"=>"✓","authenticity_token"=>"[omitted]",
    "user"=>{"username"=>"testuser1", "password"=>"test", 
    "password_confirmation"=>"test", "email_attributes"=>{"email"=>"d@d.com"}, 
    "first_name"=>"test", "last_name"=>"user", "gender"=>"male", "city"=>"la", 
    "state"=>"ca", "country"=>"usa", "dob"=>"1980-11-20"}, 
    "commit"=>"Create Account", "action"=>"create", "controller"=>"users"} 

So it appears that the password and password_confirmation attributes are getting passed correctly. I am wondering if this may have to do with the virtual attribute password I have defined in the user model, but if that is the case I am still not quite sure how to solve this problem. Any help would be greatly appreciated. Let me know if I need to elaborate further.

Here is relevant code for reference:

Controller:

class UsersController < ApplicationController

def new
  @user = User.new
  @user.build_email
end

def create
  if @user = User.create(user_params)
    logger.debug "#{@user.errors.messages}"
    logger.debug "params: #{params}"
    redirect_to :action => "new"
  else
    logger.debug "#{@user.errors.messages}"
    logger.flush
    redirect_to :action => "new"
  end
end
private
  def user_params
    params.require(:user).permit(:username, :password, :password_confirmation, :first_name, :last_name, :gender, :dob, :city, :state, :country, :admin_level, email_attributes: [:email])
  end
end

Model:

class User < ActiveRecord::Base
  has_one :email

  validates_presence_of :username, :email, :password

  validates_confirmation_of :password, :on => :create

  accepts_nested_attributes_for :email

  def password_valid?(candidatePass)
    candidatePassAndSalt = "#{candidatePass}#{self.salt}"
    candidatePasswordDigest = Digest::SHA1.hexdigest(candidatePassAndSalt)
    if (candidatePasswordDigest == self.password_digest)
      return true
    else
     return false
   end
end

  def password
  end

  def password=(text)
    self.salt = Random.new.rand
    passAndSalt = "#{text}#{self.salt}"
    self.password_digest = Digest::SHA1.hexdigest(passAndSalt)
  end
end

View:

<%= form_for @user, url: {action: "create"}, html: {class: "user-creation-form"} do |f| %>
  <%= f.text_field :username %>username<br/>
  <%= f.password_field :password %>pw<br/>
  <%= f.password_field :password_confirmation %>pwcopy<br/>
  <%= f.fields_for :email do |email_form| %>
    <%= email_form.text_field :email %>email<br />
  <% end %>
  <%= f.text_field :first_name %>first<br/>
  <%= f.text_field :last_name %>last<br/>
  <%= f.radio_button :gender, "male" %>
  <%= f.label :gender_male, "M" %>
  <%= f.radio_button :gender, "female" %>
  <%= f.label :gender_female, "F" %><br />
  <%= f.text_field :city %>city<br/>
  <%= f.text_field :state %>state<br/>
  <%= f.text_field :country %>country<br/>
  <%= f.date_field :dob %>dob<br/>
  <%= f.submit "Create Account" %><br/>
<% end %>
drdalton
  • 271
  • 3
  • 8
  • I know I'm getting boring repeating it, but - you should not write your own authentication. This is complicated matter and you will get it wrong. – Mike Szyndel Jul 19 '13 at 09:14
  • I see. How should I tackle authentication then? Is there a specific gem or library I should use? Or does rails have a built in feature? Thanks. – drdalton Jul 19 '13 at 16:17
  • I would recommend Devise which became de-facto standard, but you may browse here https://www.ruby-toolbox.com/search?q=authentication – Mike Szyndel Jul 19 '13 at 17:54
  • Cool thanks Michael, I will definitely look into this. So far it looks like it'll save me a ton of time! – drdalton Jul 19 '13 at 20:36

2 Answers2

1

The issue is your empty getter:

def password
end

It always return nil.

apneadiving
  • 114,565
  • 26
  • 219
  • 213
0

2 small additions to the previous answer, which should resolve your issue by the way.

1) If you're using Rails >3 (I assume you are by looking at your user_params method in the controller) you don't have to specify all those password fields and validations. ActiveRecord automatically includes this ActiveModel method :

has_secure_password

More details at : http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password

2) If the uncrypted password/password_confirmation are shown in your log files your app is insecure. Add this to your config/application.rb :

config.filter_parameters = [:password, :password_confirmation]

This should not be needed if you are using has_secure_password in your User model.