Authlogic, can't update user because of validation - ruby-on-rails

I've got authlogic setup as such
acts_as_authentic do |config|
config.login_field = 'email'
config.merge_validates_length_of_email_field_options :in => 5..50
config.validates_length_of_password_field_options = {:on => :update, :minimum => 4 }
config.validates_length_of_password_confirmation_field_options = {:on => :update, :minimum => 4}
end
I can't update user attributes because the password and password_confirmation try to get validated on save and they are nil. Is there any way to turn validations off temporarily, or a better solution?

Here's how it works for me:
Add a condition to your validate statements like this:
config.validates_length_of_password_field_options = {:on => :update, :minimum => 4, :if => :should_validate? }
Then add a custom should_validate? function to your user model. For example you could do
attr_accessor :updating_password
def should_validate?
updating_password or new_record?
end
This way you can explicitly set user.updating_password = true in your controller anytime you want the password to be validated and leave it as it is if you don't want any validation.
(This is my first answer, so I hope it's helpful for you. Otherwise don't hesitate to correct me.)

Related

Validating all attributes except one in Rails

I'm trying to do a custom validation in my model using valid? method. I need to run all validations of this model, except the password.
Something like this:
#resource = SalesPartner.new(permitted_params.merge(parent: current_sales_partner))
respond_to do |format|
if #resource.valid?(except: :password)
#resource.generate_authentication_token
SalesPartnerMailer.mail_new_sales_partner(#resource.email,
{ auth_token: #resource.authentication_token, id: #resource.id, level: #resource.level }
).deliver
flash[:success] = "#{#resource.level} criado com sucesso."
format.html { render "#{#path}/index" }
else
logger.log_and_alert_save_error(#resource, flash, "Ocorreu um erro ao salvar.")
format.html { render "#{#path}/new" }
end
end
Is that possible?
Thanks everyone!
Any way here is a way that you can do with the help of context. Say you have a User model and you want to validates some fields.
validates_presence_of :name,: email, on: :special_context
validates_presence_of :name,:email, :password
With the above 2 lines, you can now do like below
#user.valid?(:special_context)
The above will validates name and email fields. And if you write now,
#user.valid?
This will perform the presence validations on the name, email and password fields as you wrote.
Read valid?(context = nil) to understand the context.
Runs all the validations within the specified context. If the argument is false (default is nil), the context is set to :create if new_record? is true, and to :update if it is not.
Validations with no :on option will run no matter the context. Validations with some :on option will only run in the specified context.
Check this documentation also as an official example.
Context could really help you, but following maybe not.
validates_presence_of :name,: email, on: :special_context
validates_presence_of :name,:email, :password
This is because when you use validates_presence_of without specifying its context, it will be applied to all context(nil). Please see ref here So, maybe you could try as follow code:
validates_presence_of :name, :email, on: :special_context
validates_presence_of :name, :email, :password, on: [ :create, :update]
Just found one more mechanism to skip some validation on specified context, because specify all other context is not always suitable:
validates_presence_of :name, :email, on: :special_context
validates_presence_of :name, :email, :password, if: -> {Array(validation_context).exclude?(:special_context)}
note: validation_context can be array.

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.

Ruby on Rails Change Order of Custom Model Validations

I have a form that has model validations which works properly in my local system however when i check it on live site the order of the model validations order gets changed although the code is same in both.
this is the block of code in model:
def validate
#email validation
if !email.blank?
#errors.add(:email,I18n.t(:ismissing))
#else
if email != email_confirmation
errors.add(:email,I18n.t(:ErrorMessageConfirmEmailNotmatch))
else
if email.length <=200 then
if email.match(/^[^#][\w.-]*#[\w.-]+[.][a-z]{2,4}$/i).nil?
errors.add(:email,I18n.t(:ErrorMessageInvalid))
else
if #new_record==true
if User.find(:all, :conditions => ['lower(email) = ?', email.downcase]).count>0
#errors.add(:email," ID already exists. Provide another Email ID")
errors.add(:email,I18n.t(:ErrorMessageAlreadyExists))
end
else
if #changed_attributes["email"]!=nil
if User.User.find(:all, :conditions => ['lower(email) = ?', email.downcase]).count>0
#errors.add(:email," ID already exists. Provide another Email ID")
errors.add(:email,I18n.t(:ErrorMessageAlreadyExists))
end
end
end
end
else
errors.add(:email, I18n.t(:ErroeMessageMustlessthen,:size=>200))
end
end
else
errors.add(:email,I18n.t(:ismissing))
end
#end : Email validation
if email_confirmation.blank?
errors.add(:email_confirmation,I18n.t(:ismissing))
end
#pasword validation
if #new_record==true
if password.blank?
errors.add(:password,I18n.t(:ismissing))
else
if password_confirmation != password
errors.add(:password,I18n.t(:ErrorMessageConfirmPasswordNotmatch))
end
if !password.nil?
if password.length < 4 || password.length > 50 then
errors.add(:password,I18n.t(:ErroeMessageShouldBetween,:from=>"4",:to=>"50"))
end
errors.add(:password,I18n.t(:ErrorMessageInvalidPassword)) if password.match('^[a-z0-9##*-_]*$').nil?
end
end
end
#end password validation
if #new_record==true
if password_confirmation.blank?
errors.add(:password_confirmation,I18n.t(:ismissing))
end
end
if dob.blank?
errors.add(:dob,I18n.t(:ErrorMessageInvalid))
else
begin
#dt = DateTime.strptime(dob, "%m/%d/%Y").to_date
if dob.year <= 1900 then
errors.add(:dob,I18n.t(:ErrorMessageInvalidYear))
end
if dob>=Date.today then
errors.add(:dob,I18n.t(:ErroeMessageInvalidBirthday))
end
rescue Exception => ex
#errors.add(:dob,'is Invalid (MM/DD/YYYY format)')
errors.add(:dob,I18n.t(:ErroeMessageInvalidBirthday))
end
end
end
and the controller calls the Validate method on registration.An urgent help is required If anybody has any suggestions or ideas .
Thanks in Advance
You can use rails default validations..I did for email and gave you the sample here..
validates :email,
:presence =>{ :message => I18n.t(:ismissing)},
:length => {:allow_blank => true, :maximum => 200, :message => I18n.t(:ErroeMessageMustlessthen,:size=>200)},
:format => {:allow_blank => true, :with => /^[^#][\w.-]*#[\w.-]+[.][a-z]{2,4}$/i, :message => I18n.t(:ErrorMess
:uniqueness => {:allow_blank => true, :message => I18n.t(:ErrorMessageAlreadyExists)},
:confirmation => {:message => I18n.t(:ErrorMessageConfirmEmailNotmatch)}
Likewise you can also do for other fields.
Not sure why these wouldn't be executing in order. Have you logged something to indicate that in production?
Rather than put everything in a big validate method, maybe split into several (probably a better practice in general), then call in the order you want.
eg.
before_save :validate_email, :validate_dob
def validate_email
...
end
def validate_dob
...
end

validates_acceptance_of terms checkbox and Facebook connect

How can you force terms and condition acceptance whith facebook connect ?
In my OmniauthCallbacksController i tried
#user_ipad.terms = true
Validation of the User still fails and the user gets redirected to the sign_up form with an error message.
/app/controllers/OmniauthCallbacksController
#user_ipad = UserIpad.new(:password => Devise.friendly_token[0,20])
#user_ipad.update_with_facebook_infos(omniauth)
#user_ipad.authentication_ways.build(:provider => omniauth['provider'], :uid => omniauth['uid'])
#user_ipad.terms = true
if #user_ipad.save()
sign_in_and_redirect #user_ipad, :event => :authentication
else
session["devise.facebook_data"] = omniauth
render :action=>'new', :controller=>'user_ipads', :layout => 'empty_layout'
end
/app/models/User
attr_accessible :terms
...
validates_acceptance_of :terms, :allow_nil => false, :message => "Vous devez accepter les conditions générales d'utilisation", :on => :create
Thanks for your help,
Vincent
validates_acceptance_of has an "accept" option. Rails doc says :
:accept - Specifies value that is considered accepted. The default
value is a string “1”, which makes it easy to relate to an HTML
checkbox. This should be set to true if you are validating a database
column, since the attribute is typecast from “1” to true before
validation.
So in your case, you should replace
#user_ipad.terms = true
with :
#user_ipad.terms = "1"

Rails, Alphanumeric validation in the controller

In my app I let users select a username, just like the twitter signup page: https://twitter.com/signup
When the user starts typing a username, I want in real-time to let the user know if the username is available & valid.
The regex I've been using to validate the username is alphanumeric is:
/^[a-z0-9]+[-a-z0-9]*[a-z0-9]+$/i
Given params[:username]
In the controller, how can I validate if the username is alphanumeric or not. Note, I'm not saving the record here just validation. so a model validation wouldn't work.
Ideas? Thanks
You'd still want to use model validations.
Something like this perhaps:
class User
validates :username, :format => { :with => /your regex/ }, :uniqueness => true
end
# then in some controller action or rack app
def test_username
user = User.new(:username => params[:username])
# Call user.valid? to trigger the validations, then test to see if there are
# any on username, which is all you're concerned about here.
#
# If there are errors, they'd be returned so you can use them in the view,
# if not, just return success or something.
#
if !user.valid? && user.errors[:username].any?
render :json => { :success => false, :errors => user.errors[:username] }
else
render :json => { :success => true }
end
end
r = /^[a-z0-9]+[-a-z0-9]*[a-z0-9]+$/i
unless your_string.match(r).nil?
# validation succeeded
end
I think your regex is a little overly verbose. I'd actually try the following regex for the alphanumeric validation:
/\A[A-Z0-9]+\z/i

Resources