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
Related
I have two models: card and lane, where a lane has many cards and a card belongs to a lane.
def create
lane = lane_find
card = lane.cards.build(card_params)
if card.save
respond_with lane, :include => :cards
else
respond_with({ :errors => card.errors.full_messages }, :status => 422, :location => nil)
end
end
def update
card = Card.find(params[:id])
if card.update_attributes(card_params)
respond_with card.lane
else
respond_with({ :errors => card.errors.full_messages }, :status => 422, :location => nil)
end
end
(Note: lane_find is a private function not shown here but it simply does Lane.find(params[:lane_id]))
The intended behaviour is for the API client to receive a 422 error code when it does not save correctly, and to pass the errors alongs (such as being non-unique or being blank).
The strange thing is the create action works perfectly, as intended, while the update and destroy actions (not shown here) always return 204 on invalid input!
Testing manually on the command-line shows that the validations are set up correctly and card.update_attributes(content: "") returns false.
This is really bugging me! I would love your feedback :)
EDIT: card.rb
class Card < ActiveRecord::Base
validates :content, :uniqueness => {:case_sensitive => false}, :length => { minimum: 1 }, presence: true
belongs_to :lane
end
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
I check for
validates :group_id, :presence => true
in my model "project". Yet when I create a project without a group_id, I don't get a validation-error. If I try to do
p = Project(:name => "Test")
p.save
the rails console returns false, with save! it tells me the validation for group_id failed. So the validation is somehow performed on the save method, yet it isn't by default in my app. Do I have to do a manual
if #project.save == true
...
end
or something in my controller?
Thank you,
B
You can check #project.valid? before save.
def signup
if request.post?
#user_data = UserData.new(:login => params[:user], :password => params[:password])
if #user_data.valid?
if #user_data.save
session[:cuser] = UserData.authenticate(#user_data.login, #user_data.password).login
redirect_to(:controller=> 'sync', :action=> 'all')
return
end
else
#error_on_signup = true
end
end
I am hoping to get some help solving a problem that I'm sure many of you could avoid in your sleep.
I have two models in a habtm relationship. A package can have many locations, and a location can have many packages. If my location model fails validation (due to an empty location address, for example), I get anActiveRecord:RecordInvalid exception. I understand that I'm getting this error because when I call package.save, rails automatically calls save! on the location association.
I'm not sure how to avoid the error or at least rescue the error. Do any of you have any good advice, both on how to solve the problem and on Rails best practices?
Here is the code:
def create
#package = current_user.package.build(params[:package])
package_location
if #package.save
flash[:success] = "Package created!"
redirect_to root_path
else
render 'pages/home'
end
end
def package_location
gps_processing if !session[:gps_aware]
#package.locations.build(:address => session[:address])
end
def gps_processing
session[:address] = [params[:story][:street_address], params[:story][:city], params[:story][:state], params[:story][:country]].compact.join(', ')
end
class Package< ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :locations
validates :content, :presence => true,
:length => {:maximum => 140}
validates :user_id, :presence => true
default_scope :order => 'package.created_at DESC'
end
class Location < ActiveRecord::Base
attr_accessible :lng, :lat, :address
validates :lng, :presence => true
validates :lat, :presence => true
validates :address, :presence => true
geocoded_by :full_street_address, :latitude => :lat, :longitude => :lng
before_validation :geocode
has_and_belongs_to_many :packages
def full_street_address
address
end
end
`
Thanks in advance for your help!
The selected answer is not accurate. According to documentation here there's a simple way to catch rescue this exception:
begin
complex_operation_that_calls_save!_internally
rescue ActiveRecord::RecordInvalid => invalid
puts invalid.record.errors
end
You can access the messages instance variable of errors and get the field and error message associated.
A couple ideas off the top of my head:
Use #package.save! and a rescue block:
def create
#package = current_user.package.build(params[:package])
package_location
#package.save!
flash[:success] = "Package created!"
redirect_to root_path
rescue
render 'pages/home'
end
Use validates_associated in your Package model, and only save if it's valid:
def create
#package = current_user.package.build(params[:package])
package_location
# You might be able to just use if(#package.save), but I'm not positive.
if(#package.valid?)
#package.save!
flash[:success] = "Package created!"
redirect_to root_path
else
render 'pages/home'
end
end
And I'm sure there are a couple more ways, too, as you're working in Ruby...
Hope that helps!
Here's the code that I used to solve the problem while giving the user good feedback on the why the save failed. Please forgive my inelegant ruby code.
One small problem remains . . . if the package and the location both fail validation, only the location error message is displayed on reload. If the user then corrects the location error but not the package error, he is shown the package error message. I'm working on how to show all of the errors on the first reload
def create
#package= current_user.package.build(params[:package])
if package_location && #package.save
flash[:success] = "Package created!"
redirect_to root_path
else
render 'pages/home'
end
end
def package_location
gps_processing if !session[:gps_aware]
location = #package.locations.build(:address => session[:address])
if !location.valid?
#package.errors.add(:address, "You have entered an invalid address")
return false
else
return true
end
end
def gps_processing
session[:address] = [params[:story][:street_address], params[:story][:city],
params[:story][:state], params[:story][:country]].compact.join(', ')
end
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.)