Validate fields only if virt_attribute is false - ruby-on-rails

I have such model:
class Order < ActiveRecord::Base
attr_accessible :**** :phone_number, :receiver, :shipping_id, :street, :totalcost, :user_id, :zip, :use_user_data
attr_accessor :use_user_data
validates :city, :presence => {:message => I18n.t(:city_not_chosen)}
validates :zip, :presence => {:message => I18n.t(:zip_not_chosen)}
validates :street, :presence => {:message => I18n.t(:street__not_chosen)}
validates :building, :presence => {:message => I18n.t(:building_not_chosen)}
validates :phone_number, :presence => {:message => I18n.t(:phone_number_not_chosen)}
validates :receiver, :presence => {:message => I18n.t(:receiver_not_chosen)}
end
As you can see i set in model some field which is non-db field (use_user_data) - virtual attribute...
But how to do, if :use_user_data is false, good and right validate, but when true didn't validate?
i try so:
validates :city, :presence => {:message => I18n.t(:city_not_chosen)}, :unless => :use_user_data
and so
with_options :unless => :use_user_data do |order|
order.validates :city, :presence => {:message => I18n.t(:city_not_chosen)}
end
but it doesn't help me... Why?
Also my form:
= form_for #order do |f|
%div
= f.label :use_user_data , "Использовать данные вашего профиля*: "
= label :use_user_data , "Да"
= f.radio_button :use_user_data, true, :required => true, :id => "use_user_data", :checked => true
= label :use_user_data , "Нет"
= f.radio_button :use_user_data, false, :required => true, :id => "dont_use_user_data"
Also when i write
validates :city, :presence => {:message => I18n.t(:city_not_chosen)}, :if => :use_user_data
i get validation messages... But how to do only if false? And why my solution didn't work?

The form passes "true" or "false" string to the object, not boolean true or false. Since it's a virtual attribute, no typecasting performed. In Ruby, both "true" and "false" are true, so you need to use something to typecast the value
with_options :unless => Proc.new{ |a| a.use_user_data == 'true' } do |order|
order.validates ...
end
Or
with_options :unless => :use_user_data? do |order|
order.validates ...
end
def use_user_data?
use_user_data == 'true'
end

You need to put your :if or :unless conditions in a lambda or Proc.
validates ..., :if => Proc.new { |a| a.use_user_data === false }
This causes the check against :use_user_data to not be evaluated until the above validates line is executed during validation (the Proc is passed as the value to the :if or :unless option to be evaluated by Rails). The Proc will receive the current model attributes as an argument, allowing you to check those attributes (in this case, :use_user_data being false).

Related

Setting up message for validation rules

I have this validation rule:
validates :email, :presence => {:message => 'Email cannot be blank.'}, :allow_blank => true, :format => {:with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/, :message => 'Email is not valid.'}, :uniqueness => true
and I would like to set up own message for
validates :email, :presence => {:message => 'Email cannot be blank.'}, :allow_blank => true, :format => {:with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/, :message => 'Email is not valid.'}, :uniqueness => {message: 'This email address has already been taken.'}
But this generate only the default message has already been taken, not the one I defined in the message part. How to customise it?
Thanks

Validates presence of THIS or THAT

I have a form where the user is prompt to enter a title and either :this or :that. A user can't enter both fields.
<% f.input :title%>
<% f.input :this %>
<% f.input :that%>
for my :title i have in my Model
validates :title, :presence => true
How can i pass a validation for either :this or :that
You can do this
validates :that, :presence => true, :if => Proc.new {this.blank?}
validates :this, :presence => true, :if => Proc.new {that.blank?}
Wouldn't just the first line be sufficient?
validates :that, :presence => true, :if => Proc.new {this.blank?}
If 'this' is blank and so is 'that', the first line would fail validation, so you wouldn't need the second line.

Rails 3 Active record validation error messages with unwanted/extra characters

I'm workin on ROR app using Rails 3.2.9 and I'm getting the error messages for a sign up page in my app as follows
<li>Login is too short (minimum is 3 characters)</li><li>Email is too short (minimum is 7 characters)</li><li>Email is invalid</li><li>Password can't be blank</li><li>Password is too short (minimum is 4 characters)</li><li>Password is invalid</li><li>Password confirmation can't be blank</li>
These are the default messages of Active Record Validation . (ref: http://guides.rubyonrails.org/active_record_validations_callbacks.html )
This app was previously written in Rails 2 and later migrated to rails 3. I have changed the validates_presence_of commands to validates : password , :presence=>true etc in accordance with rails 3 .
In the view ( signup.html.erb) error_messages_for is rendering these msgs. It is deprecated from rails 3.
Can anyone tell me what needs to be used instead of error_messages_for in the view and all code needs to be changed correspondingly for getting the error msgs right..
Here's the code (not complete)
user.rb in app/model
class User < ActiveRecord::Base
has_many :excel_files # One user may have many excel files
has_one :user_access_validity# One user may have one license period
# Virtual attribute for the unencrypted password
attr_accessor :password
attr_accessible :login
attr_accessible :email
attr_accessible :password
attr_accessible :password_confirmation
attr_accessible :company
#changes of 'validates' in accordance with rails 3:
validates :login, :presence => true,
:length => { :within => 3..40},
:uniqueness => { :case_sensitive => false },
:format => { :with => /^([a-z_0-9\.]+)$/i },
:on => :create,
:if => :is_login_entered?
validates :email, :presence => true,
:length => { :within => 7..100},
:uniqueness => { :case_sensitive => false },
:format => {:with => /^([a-z]+((\.?)|(_?))[a-z0-9]+#(mindtree.com|rvce.edu.in))$/i},
:on => :create,
:if => :is_email_entered?
validates :company, :presence => true,
:format => { :with =>/(mindtree|RVCE)/i},
:format => { :with => /^([a-z]+)$/i },
:on => :create,
:if => :is_company_entered?
#validates_presence_of :login, :email, :company
on => :create, :if => :is_login_entered?
validates :password, :presence => true,
:length => { :within => 4..40 },
:confirmation => true,
:format => { :with => /^([a-z0-9#!#\$]+)$/i },
:on => :create,
:if => :password_required?
validates :password_confirmation, :presence => { :if => :password_required? }
#validates_presence_of :password_confirmation, :if => :password_required?
before_save :encrypt_password
.
.
.
In signup.html.erb
<font color=red>(Fields marked * are mandatory)</font><h3>Sign me up!</h3>
<br>
<span class='error'><%= error_messages_for (#user) %></span>
<%= form_for :user do |f| -%>
<p><label for="login"><span class='redcolor'>*</span>Login</label><br/>
<%= f.text_field :login %></p>
<p><label for="email"><span class='redcolor'>*</span>Email</label><br/>
<%= f.text_field :email %></p>
<p><label for="password"><span class='redcolor'>*</span>Password</label><br/>
<%= f.password_field :password %></p>
<p><label for="password_confirmation"><span class='redcolor'>*</span>Confirm Password</label><br/>
<%= f.password_field :password_confirmation %></p>
<p><label for="company"><span class='redcolor'>*</span>Company</label><br/>
<%= f.text_field :company %></p>
<p><%= submit_tag 'Sign up' %></p>
<% end -%>
Solution
Got the following code from http://www.rubydoc.info/github/edavis10/redmine/ApplicationHelper:error_messages_for which shud be added in application_helper.rb and corresponding change in html.erb file as <%= error_messages_for (#user) %>
Code:
def error_messages_for(*objects)
html = ""
objects = objects.map {|o| o.is_a?(String) ? instance_variable_get("##{o}") : o}.compact
errors = objects.map {|o| o.errors.full_messages}.flatten
if errors.any?
html << "<div id='errorExplanation'><ul>\n"
errors.each do |error|
html << "<li>#{h error}</li>\n"
end
html << "</ul></div>\n"
end
html.html_safe
end
http://guides.rubyonrails.org/active_record_validations_callbacks.html
if you read this guide you will see that in you form you can use form.error_messages
Solution for the question is added below the question

Rails3: Display validate errors in a multi-model Form?

Is posible create this kind forms with displaying errors like a simple model?
http://i.imgur.com/8t6ef.png
I get create two models... but if I fill incorrectly the form.. the errors messages won't appears and error Rails screen say me, for example, "validation failed: field1 can't be blank..."
http://i.imgur.com/6KvVh.png
Models:
class Step < ActiveRecord::Base
#validates
validates :tree_id, :presence => true, :numericality => true
validates :is_first, :presence => true, :length => {:maximum => 1}
validates :status, :presence => true, :numericality => true
validates :step_type_id, :presence => true
#relations
belongs_to :step_type
belongs_to :tree
has_many :statements
accepts_nested_attributes_for :statements
end
class Statement < ActiveRecord::Base
#validates
validates :step_id, :presence => true, :numericality => true
validates :title, :presence => true, :length => {:maximum => 255}
validates :statement, :presence => true
validates :help, :presence => true
validates :is_last_version, :presence => true, :length => {:maximum => 1}
#relations
belongs_to :step
has_many :transitions
end
any example or suggestions?
Do you have the following lines in your view?
<% if #statement.errors.any? %>
<% flash[:notice] = "Please correct!" %>
<% for message in #statement.errors.full_messages %>
<li class="cf-messages-li"><%= message %></li>
<% end %>
<% end %>

How to update only part of attributes, not all, in rails

I have an edit form for updating some attributes. But it tryes to edit all attributes, and cause of this I have validation error.
My form (edit view)
#person_info.fl_l
- if #user.errors.any?
.error_explanation
%h2 Form is invalid
%ul
-for message in #user.errors.full_messages
%li= message
=form_for #user do |f|
%p
Birthday:
%br
= f.date_select(:birthday,:start_year => 1940)
%p
Name:
%br
= f.text_field :name, :value=>#user.name
%p
Surname:
%br
= f.text_field :surname, :value=>#user.surname
%p
Nickname:
%br
= f.text_field :nickname, :value=>#user.surname
%p
About Myself:
%br
= f.text_area :about_myself, :value=>#user.about_myself
%p
= f.submit "Update"
My update and edit actions:
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
redirect_to #user
else
render 'edit'
end
end
When I submit the form, it outputs validation errors like: "Password can't be blank"
So, how to update only part of attributes, not all? I dont want to update password in my case.
My user model
class User < ActiveRecord::Base
has_many :posts
has_many :sent_messages, :class_name => "Message", :foreign_key => "sender_id"
has_many :received_messages, :class_name => "Message", :foreign_key => "receiver_id"
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, :presence => true,
:length => {:maximum => 50}
validates :email, :presence => true,
:format => {:with => email_regex},
:uniqueness => {:case_sensitive => false}
validates :password, :presence => true,
:confirmation => true,
:length => {:within => 6..40}
before_create { generate_token(:auth_token) }
def send_password_reset
generate_token(:password_reset_token)
self.password_reset_sent_at = Time.zone.now
save!
UserMailer.password_reset(self).deliver
end
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
end
Remove it from the params hash
params.delete(:password)
Or build your own hash to send to update.
Checkout Authentication in Rails 3.1 to smoothen out your authentication. it takes out a lot of code from your model.
Then, I noticed that: if a field is hidden from the form for any reason, rails does not pass this in the params hash for an update. So you can play with hiding fields in a form. This is how I solve mine.
I fixed this issue by appending
,:on => :create
to my validates_presence_of and validates_length_of lines.
I believe your model is invalid in its current state ... you're not sending in the password, so Rails is not touching that attribute.
In rails console, test:
user = User.find(whatever_the_id_is)
puts user.valid?
puts user.errors.inspect
My hypothesis is that it is invalid --- due to a missing password.
I have solved this in the User password validation like so:
validates :password, :presence => true,
:confirmation => true,
:if => :password # only validate if password changed!

Resources