validates_confirmation_of in Rails preventing me from saving a new object - ruby-on-rails

In my User.rb model, I have this line:
validates_confirmation_of :password, :message => "Your passwords should match."
Then when the user signs up, the passwords match, everything is great... until I want to add more information to the user object, then save again. But running #user.save returns the error that my passwords don't match. In my signup controller method, I have these lines:
#user = User.new(params[:user])
if request.post?
if !#user.save
#errors = #user.errors
else
# crucial user details:
#user.salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
#user.password = encrypted_password(#user.password, #user.salt) #hash this
if !#user.save
puts "error for some reason in signup"
puts #user.errors.inspect
end
And upon inspection, #users.errors.inspect prints out: #["Your passwords should match."]}. They did, otherwise, it would never have passed the first .save call. Any advice on what I'm doing wrong here?
Thanks for your help.

This fixed it:
validates_confirmation_of :password, :on => :create, :message => "Your passwords should match."

Related

Show information after record creation on ActiveAdmin

I want to let the admin user see a particular message after or before or during he creats a new record.
I need either an alert box after he created the new record, or to change the current confirmation message just for the user model, or to add a small text in the form specifying this.
I can't seem to find any of the ways.
Thank you
You need to use "notice:". In my case, after saving new "admin_user", I am checking for "resource". If it is "valid", then "redirect_to" with a "message". ... This always works for me.
ActiveAdmin.register AdminUser do
....
....
permit_params :first_name, :last_name, :email, :password
def create
#admin_user = AdminUser.new( admin_user_params )
#admin_user.save
if resource.valid?
redirect_to collection_url, notice: 'Creation Success'
else
flash[:alert] = 'Creation Failed'
render :new
end
end
private
def admin_user_params
params.require(:admin_user).permit(:id, :first_name, :last_name, :email, :password)
end
end
you can modify the flash message with an after_create callback for that case, something like this
ActiveAdmin.register User do
permit_params :name, :email, :password
after_create do |user|
flash[:notice] = "User has been created with the default password" if user.valid?
end
end

user.save returns false in console, but true when done via the UI

I'm a programming/rails beginner, and have encountered a bug I cannot wrap my head around.
I'm using/learning about the "has_secure_password" method. When I try and create a user in my console with a mismatched password/confirm_password, the console returns false and the error is "Password confirmation doesn't match Password". But, when I try and do the same thing within the UI given the below code (+ a view), it saves just fine! Now, notice that in my "user_params" method, I accidentally forgot to permit ":password_confirmation" which is how I noticed this issue in the first place. With that ":password_confirmation" added, the view throws an error but that's not the point. Why even without this is the new User record being successfully created with a mismatched password and password confirmation, even though it doesn't save in the console?
Here is my User model:
class User < ActiveRecord::Base
has_secure_password
validates :name, presence: true
validates :email, presence: true, format: /\A\S+#\S+\z/, uniqueness: {case_sensitive: false}
validates :password, length: {minimum: 4, allow_blank: true}
end
And my User controller:
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to #user, notice: "Thanks for signing up!"
else
render :new
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password)
end
end
This is happening because the password_confirmation attribute is optional. When it isn't supplied to the model that has_secure_password, the model simply accepts the password.
When your password confirmation attribute isn't whitelisted in your controller via user_params, it isn't being passed to the model at all, which is why mismatches appears not to throw an error. In truth the validation isn't taking place at all.
This works in your console because it creates a user without involving a controller or strong parameter whitelisting.

Rails Password Change

I'll start by telling you how I want my settings page set up.
I want users to be able to change their settings without requiring a password, and that's how it is set up now with this as the user model
validates :password, presence: true, length: { minimum: 6 }, :on => :create
validates :password_confirmation, presence: true, :on => :update, :unless => lambda{ |user| user.password.blank? }
This makes it so user's can change all of their settings without requiring a password (I know some might frown on this). But i want users to be able to change their passwords on the page like so...User clicks Change Password, a modal pops up, and users have to give their current password and then the new password and a confirmation of the new one. (I know how to do modal, i just want to know how do password reset).
Does this make sense?? I believe the way Pinterest does it is a good example (although they use Python I think)
My suggestion is to use a form object:
app/forms/change_password_form.rb
class ChangePasswordForm
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
# Add all validations you need
validates_presence_of :old_password, :password, :password_confirmation
validates_confirmation_of :password
validate :verify_old_password
attr_accessor :old_password, :password, :password_confirmation
def initialize(user)
#user = user
end
def submit(params)
self.old_password = params[:old_pasword]
self.password = params[:password]
self.password_confirmation = params[:password_confirmation]
if valid?
#user.password = password
#user.password_confirmation = password_confirmation
#user.save!
true
else
false
end
end
def verify_old_password
self.errors << "Not valid" if #user.password != password
end
# This method is required
def persisted?
false
end
end
In controller initialize the form object #pass_form = ChangePasswordForm.new(current_user) and use the object in your modal: form_for #pass_form... and add the old_password, password and password_confirmation fields.
And finally, for example, in the update action:
#pass_form = ChangePasswordForm.new(current_user)
if #pass_form.submit(params[:change_password_form])
redirect_to some_path
else
render 'new'
end
I haven't tested this code, but you get the idea. Take a look to this Railscasts.

How to clear the password fill on registration/sign up error with authlogic?

I'm using Ruby 1.8.7, Rails 2.3.8, and using Authlogic 2.1.6 for registration, login, logout. In fact, those three things are nearly all I've done!
During registration, if the user has errors in their registration information, I want the password and password_confirmation fields to be empty when the view is redrawn. I assumed one could clear the fields in the UsersController, as follows:
class UsersController < ApplicationController
before_filter :require_no_user, :only => [:new, :create]
def create
#user = User.new(params[:user])
if #user.save
#user.save
flash[:success] = "Registration successful!"
redirect_back_or_default root_path
else
#user.password = ""
#user.password_confirmation = ""
#page_title = "Registration"
end
end
...
The password_confirmation field is successfully cleared by this code, but the password field is not. I inserted a debugger call just after the 'else', and sure enough, the value of #user.password is unchanged by the line '#user.password'. I am guessing that there is something in Authlogic that is restoring the field's value after I attempt to clear it. (I also tried setting it to 'nil', with the same result).
I've come up with a work-around, I'm explicitly setting the form field's value to "" in the view:
<%= form.password_field :password, :value => "" %>
But that doesn't seem to me the ideal way to handle it!
You can do what you have already or:
def create
if #user_session.save
...
else
params[:users][:password] = ''
Personally I would stick with what you have.

Force validation of blank passwords in Authlogic

I'm adding a password reset feature to my Rails application that uses Authlogic. I was following the guide here: http://www.binarylogic.com/2008/11/16/tutorial-reset-passwords-with-authlogic/ and everything works as I'd like except for one thing: the password reset form accepts blank passwords and simply doesn't change them.
I've been searching around, and have learned that this is the intended default behavior because it allows you to make user edit forms that only change the user's password if they enter a new one, and ignore it otherwise. But in this case, I specifically want to enforce validation of the password like when a user initially registers. I've found two possible solutions for this problem but haven't been able to figure out how to implement either of them.
1) Someone asked this same question on Google Groups:
User model saves with blank password
Ben's response was to use #user.validate_password = true to force validation of the password. I tried this but I get an undefined method error: undefined method 'validate_password_field=' for #<User>.
2) There seems to be an Authlogic configuration option called ignore_blank_passwords. It is documented here:
Module: Authlogic::ActsAsAuthentic::Password::Config#ignore_blank_passwords
This looks like it would work, but my understanding is that this is a global configuration option that you use in your initial acts_as_authentic call in the User model, and I don't want to change it application-wide, as I do have a regular edit form for users where I want blank passwords to be ignored by default.
Anyone found a solution to this? I see validate_password= in the change log for Authlogic 1.4.1 and nothing about it having been removed since then. Am I simply using it incorrectly? Is there a way to use ignore_blank_passwords on a per-request basis?
This is kind of an old thread, but since it is unanswered I'll post this.
I've managed to do it a bit more cleanly than the other solutions, "helping" authlogic validations with my own.
I added this to user:
class User < ActiveRecord::Base
...
attr_writer :password_required
validates_presence_of :password, :if => :password_required?
def password_required?
#password_required
end
...
end
You can reduce it to two lines by making an attr_accessor and using :if => :password_required (no interrogation), but I prefer this other syntax with the interrogation sign.
Then your controller action can be done like this:
def update
#user.password = params[:user][:password]
#user.password_confirmation = params[:user][: password_confirmation]
#user.password_required = true
if #user.save
flash[:notice] = "Password successfully updated"
redirect_to account_url
else
render :action => :edit
end
end
This will have a local effect; the rest of the application will not be affected (unless password_required is set to true in other places, that is).
I hope it helps.
This what I did.
class User < ActiveRecord::Base
attr_accessor :ignore_blank_passwords
# object level attribute overrides the config level
# attribute
def ignore_blank_passwords?
ignore_blank_passwords.nil? ? super : (ignore_blank_passwords == true)
end
end
Now in your controller, set the ignore_blank_passwords attribute to false.
user.ignore_blank_passwords = false
Here, you are working within the confines of AuthLogic. You don't have to change the validation logic.
User.ignore_blank_passwords = false
Use model, not object for setting this property.
def update_passwords
User.ignore_blank_passwords = false
if #user.update_attributes(params[:user])
...
end
User.ignore_blank_passwords = true
end
Maybe test the value of the parameter in the controller? (air code):
def update
#user.password = params[:user][:password]
#user.password_confirmation = params[:user][: password_confirmation]
if #user.password.blank?
flash[:error] = "Password cannot be blank"
render :action => :edit
return
end
if #user.save
flash[:notice] = "Password successfully updated"
redirect_to account_url
else
render :action => :edit
end
end
Apart from zetetic's solution you could do it this way:
def update
#user.password = params[:user][:password]
#user.password_confirmation = params[:user][: password_confirmation]
if #user.changed? && #user.save
flash[:notice] = "Password successfully updated"
redirect_to account_url
else
render :action => :edit
end
end
You're basically checking if authlogic changed the user record (which it doesn't if the password is empty). In the else block you can check if the password was blank and add an appropriate error message to the user record or display a flash message.

Resources