Password confirmation in Rails 5 - ruby-on-rails

This is my view:
<%=form_for [:admin, #user] do |f|%>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<%=f.label :name %>
<%=f.text_field :name %>
<%=f.label :email %>
<%=f.text_field :email %>
<%=f.label :password %>
<%=f.password_field :password %>
<%=f.label :password_confirmation %>
<%=f.password_field :password_confirmation%>
<%=f.submit "Submit" %>
<%end%>
Controller code for adding user:
def create
#user = User.new(user_params)
if #user.save
redirect_to admin_users_path
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
These are validations in the model:
validates :name, presence: true
validates :email, presence: true
validates :password, presence: true
validates :password, confirmation: { case_sensitive: true }
But confirmation password doesn't work.
Validation works for all (they are required) form elements, except second password input - password_confirmation which can be different from first password input.
User is added to the database even if second password input is empty, because in the validation rules, there is no rule for that .
What am I doing wrong ?

You need to add password_confirmation to user_params in the controller.
I.e.
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end

Try: validates_confirmation_of :password
Model:
class Person < ActiveRecord::Base
validates_confirmation_of :user_name, :password
validates_confirmation_of :email_address, :message => "should match confirmation"
end
View:
<%= password_field "person", "password" %>
<%= password_field "person", "password_confirmation" %>
You could take a look to the validates_confirmation_of.

Related

Rails: how to let two user models in devise go through registration

In my app there are two models:
Users
Teachers
Registering Teachers is a problem because my registration controller is set up for user registration only (I think), so I keep getting errors about the params missing "user".
Registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:user).permit(:teacher, :teacher_id, :user_id, :username, :first_name, :last_name, :email, :password, :password_confirmation)
end
def account_update_params
params.require(:user).permit(:teacher, :teacher_id, :user_id, :username, :first_name, :last_name, :email, :password, :password_confirmation, :current_password)
end
end
So my questions are:
Do you know a way to tweak the registrations controller to handle both registrations?
Should I even be doing it like this or ought it be handled differently?
Just in case, here is the registration form that is being used. Thanks for your time.
devise>registrations>new.html.erb
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<div>
<%= f.input :username, required: true, autofocus: true %>
<%= f.input :email, required: true %>
<% if request.fullpath.include?('user') %>
<%= f.input :teacher_id, required: false %>
<% end %>
<%= f.input :password, required: true, hint: ("#{#minimum_password_length} characters minimum" if #minimum_password_length) %>
<%= f.input :password_confirmation, required: false %>
</div>
<div class="form-actions">
<%= f.button :submit, "Sign up" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
In your config/routes.rb
devise_for :users, controllers: { registrations: "registrations" }
devise_for :teachers, controllers: { registrations: "teacher/registrations" }
Create a controller app/controllers/teacher/registrations_controller.rb
class Teacher::RegistrationsController < Devise::RegistrationsController
private
def sign_up_params
params.require(:teacher).permit(:username, :first_name, :last_name, :email, :password, :password_confirmation)
end
def account_update_params
params.require(:teacher).permit(:username, :first_name, :last_name, :email, :password, :password_confirmation, :current_password)
end
end

"Password confirmation" message not showing up when both password fields are empty

Working through the railstutorial.org . Currently on the Update Profile page part of it. When leaving the Password and Password Confirmation fields empty, only the Password is too short error comes up, though in the tutorial screenshot Password confirmation can't be blank message is present. But, it does show up when the Password field is filled and Password Confirmation field is left empty.
edit.html.erb :
<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Save changes", class: "btn btn-large btn-primary" %>
<% end %>
<%= gravatar_for #user %>
change
</div>
</div>
users_controller.rb:
.
.
.
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
.
.
.
user.rb:
class User < ActiveRecord::Base
has_secure_password
before_save { self.email = email.downcase }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(?:\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6 }
before_create :create_remember_token
def User.new_remember_token
SecureRandom.urlsafe_base64
end
def User.digest(token)
Digest::SHA1.hexdigest(token.to_s)
end
private
def create_remember_token
self.remember_token = User.digest(User.new_remember_token)
end
end
Your User.rb model is out of sync with the one MHartl uses at that point in the tutorial. Specifically, notice that he has an explicit validates :password_confirmation, presence: true in addition to the validates :password, length: { minimum: 6 }. When you call #user.update_attributes, it hits these validators and, in his case, both fail, whereas in your User.rb model there is not the presence validator.
When you have the password field filled in, you're hitting validators defined in has_secure_password rather than in your model, which is why they appear then.
Make sure you include the password and password_confirmation in your allowed parameters in you controller:
private
def user_params
params.required(:user).permit(:name, :email, password,:password_confirmation)
end
EDIT:
As the other had already pointed out you miss the validation of password_confirmation
validates :password_confirmation, presence: true

Password Confirm not Comparing with Password

I'm not sure how to validate the confirm password element, this code seems to work, but the validates confirmation of password doesn't seem to compare the passwords as expected, just need a hand getting used to Rails 4's new ways.
Sign Up View:
Sign Up
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.text_field :email, class: "form-control", autofocus: "", required: "", placeholder: "Email address" %>
<%= f.password_field :password, class: "form-control", required: "", placeholder: "Password" %>
<%= f.password_field :password_confirmation, class: "form-control", required: "", placeholder: "Confirm Password" %><br/>
<p class="button"><%= submit_tag "Register", class: "btn btn-lg btn-primary btn-block" %></p>
<% end %>
</div>
Users Controller:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.create(user_params)
if #user.save
redirect_to root_url, :notice => "Signed up!"
else
render "new"
end
end
private
def user_params
params.require(:user).permit(:username, :email, :password, :passord_confirmation, :salt, :encrypted_password)
end
end
Users Model:
class User < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
validates_presence_of :password, on: :create
validates :password, confirmation: :true
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
private
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
It looks like your model's password confirmation may be off, unless you have your own private method confirmation
Try changing your model from validates :password, confirmation: :true to validates_confirmation_of :password
The API has some examples as well.
You need to make the password and password_confirmation accessible. For example:
attr_accessor :password
attr_accessible :password, :password_confirmation
validates :password, :presence => true,
:confirmation => true
Try adding that, and see if it makes a difference.

how to set foreign key through the controller in rails?

I've got an address form nested into a user form but cant get the foreign key to fill. I've seen people suggest using a hidden field, but that seems to be a bad idea from a security standpoint. How exactly do you set the foreign key using the controller? Right now I'm getting Address user can't be blank error when I try to submit
MVC below
user\new.html.erb
<div>
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :rank %>
<%= f.text_field :rank %>
<%= f.label :firstName, "First Name" %>
<%= f.text_field :firstName %>
<%= f.label :lastName, "Last Name" %>
<%= f.text_field :lastName %>
<%= f.label :middleInitial, "Middle Initial" %>
<%= f.text_field :middleInitial %>
<%= fields_for :address do |a| %>
<%= a.label :address %>
<%= a.text_field :address %>
<%= a.label :city %>
<%= a.text_field :city %>
<%= a.label :state %>
<%= a.text_field :state %>
<%= a.label :zip, "Zip Code" %>
<%= a.text_field :zip %>
<% end %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :dateOfBirth, "Date of Birth" %>
<%= f.text_field :dateOfBirth %>
<%= f.label :MOS, "MOS" %>
<%= f.text_field :MOS %>
<%= f.label :ets_pcsDate, "ETS/PCS Date" %>
<%= f.text_field :ets_pcsDate %>
<%= f.label :phoneNum, "Phone Number" %>
<%= f.text_field :phoneNum %>
<%= f.label :password %>
<%= f.text_field :password %>
<%= f.label :password_confirmation, "Confirmation" %>
<%= f.text_field :password_confirmation %>
<%= f.submit "Sign up" %>
<% end %>
</div>
<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>
Models
User
class User < ActiveRecord::Base
attr_accessible :MOS, :dateOfBirth, :ets_pcsDate, :firstName,
:lastName, :middleInitial, :phoneNum, :rank, :email, :password,
:password_confirmation
has_secure_password
has_one :address, dependent: :destroy
accepts_nested_attributes_for :address
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
validates :rank, presence: true
validates :firstName, presence: true, length: { maximum: 15 }
validates :lastName, presence: true, length: { maximum: 20 }
validates :middleInitial, presence: true, length: { maximum: 1 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :dateOfBirth, presence: true
validates :MOS, presence: true
validates :ets_pcsDate, presence: true
validates :phoneNum, presence: true
validates :password, length: { minimum: 6 }
validates :password_confirmation, presence: true
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
Address
class Address < ActiveRecord::Base
attr_accessible :address, :city, :state, :zip
belongs_to :user
validates :address, presence: :true
validates :city, presence: :true
validates :state, presence: :true
validates :zip, presence: true
validates :user_id, presence: true
end
Controller
class UsersController < ApplicationController
before_filter :signed_in_user, only: [:index, :edit, :update, :show, :destory]
before_filter :correct_user, only:[:edit, :update]
before_filter :admin_user, only: :destroy
def new
#user = User.new
#user.address.build
end
def create
#user = User.new(params[:user])
#address = #user.build_address(params[:address])
if #user.save
sign_in #user
flash[:success] = "Welcome to B Troop!"
redirect_to #user
else
render 'new'
end
end
def show
#user = User.find(params[:id])
end
def index
#users = User.paginate(page: params[:page])
end
def edit
end
def update
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
sign_in #user
redirect_to #user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
flash[:success] = "User removed"
redirect_to users_path
end
private
def signed_in_user
unless signed_in?
store_location
redirect_to root_path, notice: "Please sign in."
end
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
def admin_user
redirect_to(root_path) unless current_user.admin?
end
end
Removing the user_id validation did the trick.

How to get optional fields with form_for using rails?

I'm using Rails 3.2 and I'm trying to build a form to let a user update its data. However, if the user doesn't want to change its password it can do it by letting the fields blank.
Here is my code for the form :
<%= form_for(#user) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :new_password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Save changes" %>
<% end %>
And here is my method update in the users controller:
def update
if #user.update_attributes(params[:user])
sign_in #user
flash[:success] = "Profile updated"
redirect_to #user
else
render 'edit'
end
end
When I'm leaving the password's fields blank, I always get flash messages for incorrect password.
Thank you
---UPDATE---
Here is my user model:
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation, :team_id, :updating_password
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false}
validates :password, presence: should_validate_password? , length: { minimum: 6 }
validates :password_confirmation, presence: should_validate_password?
def should_validate_password?
updating_password || new_record?
end
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
I think there is a really good answer to this question here: In Rails 3, how can I skip validation of the password field when I'm not attempting to update the password?
I would repeat it, but the given answer is pretty good. Also points to a railscast on the subject.

Resources