Rails 3: Why integer field is not validated against regex? - ruby-on-rails

Job model has an integer job_price field:
class CreateJobs < ActiveRecord::Migration
def self.up
create_table :jobs do |t|
...
t.integer "job_price"
...
end
end
...
end
I would like to display an error message if user types strings in the job_price field, so I added the following validation:
class Job < ActiveRecord::Base
validates_format_of :job_price, :with => /\A\d{0,10}\z/,
:message => "^Job Price must be valid"
...
end
However, it seems like the validation passes even when I type strings.
Any ideas why ?
Note
I had to add :value => #job.job_price_before_type_cast here:
f.text_field(:job_price, :maxlength => 10,
:value => #job.job_price_before_type_cast)
because, otherwise, if I was typing abc5, for example, and then submit the form, Rails was converted it to 5 (I guess because job_price is defined as integer).

You could ensure it's an integer and in a range:
validates_numericality_of :myfield, :only_integer => true
validates_inclusion_of :myfield, :in => 0..9999999999

Rails 3 way would be:
validates :myfield, :numericality => { only_integer: true }
validates :myfield, :inclusion => { :in => 1..10000 }

ActiveModel does have a built-in validation method for integers.
validates_numericality_of
Hopefully will behave how you want it to.

Related

Validation not working on Ranges?

Can someone explain to me why my validation won't get triggered when I submit a string such as "foo" to number?
class Course < ActiveRecord::Base
validates :number, :inclusion => 0..100
end
Only when I change my code to this...
class Course < ActiveRecord::Base
validates :number, :inclusion => 0..100, :numericality => true
end
... the validation gets triggered.
Is this a Rails bug or am I missing something really fundamental here?
I am using Rails 4.2.0 by the way.
It's because rails is converting the string to a number (assuming you've got it persisted as an integer) before doing the validation. If you call to_i on a string you get 0 which is valid for your range.
For example:
> c = Course.new
> c.number = 'hi'
> c.number
=> 0
> c.valid?
=> true
The reason the numericality validators is triggering when you add it is, I think, because it checks the value before any type casting happens:
> c.number = 'hi'
> c.number_before_type_cast
=> 'hi'
Please try this:
validates_numericality_of :number, :only_integer => true,
:greater_than_or_equal_to => 1,
:less_than_or_equal_to => 99,
:message => "can only be number between 1 and 100."
ref: http://apidock.com/rails/ActiveModel/Validations/ClassMethods/validates_numericality_of
This turned out to work best for me:
class Course < ActiveRecord::Base
validates :number, :numericality => { :greater_than_or_equal_to => 0, :less_than_or_equal_to => 100 }
end

Rails: How to set different validation rules on creation and update

I have a text field that can be empty when created, but not when updated.
How can I do that in rails: Different validation rules depending on action?
The idea behind this, is to allow an admin to create a blank issue ticket, to be filled by a user.
Here is my original model (issue.rb):
class Issue < ActiveRecord::Base
attr_accessible :content, :status
validates :content, :presence => true, :length => { :maximum => 2048 }
validates :status, :inclusion => { :in => %w(WAITING REJECTED ON OFF) }
belongs_to :user
end
How can I set :presence => true of :content only when updating, but not when creating?
Thanks in advance.
You can use :on => :create in your validation statement.
Like in this question.

Validates acceptance always failing

I can't see what I'm missing, but something is obviously not right.
In model:
validates :terms, :acceptance => true, :on => :update
Trying a few options:
>> a = Factory(:blog_agreement)
=> #<BlogAgreement id: 54, terms: false, created_at: "2011-01-20 11:33:03", updated_at: "2011-01-20 11:33:03", accept_code: "fa27698206bb15a6fba41857f12841c363c0e291", user_id: 874>
>> a.terms
=> false
>> a.terms = true
=> true
>> a.save
=> false
>> a.terms = "1"
=> "1"
>> a.save
=> false
>> a.terms = 1
=> 1
>> a.save
=> false
>> a.errors.full_messages
=> ["Terms must be accepted"]
Updated answer..
So it turns out that the problem was having terms as an actual column in the table. In general validates_acceptance_of is used without such a column, in which case it defines an attribute accessor and uses that for its validation.
In order for validates_acceptance_of to work when it maps to a real table column it is necessary to pass the :accept option, like:
validates :terms, :acceptance => {:accept => true}
The reason for this has to do with typecasting in Active Record. When the named attribute actually exists, AR performs typecasting based on the database column type. In most cases the acceptance column will be defined as a boolean and so model_object.terms will return true or false.
When there's no such column attr_accessor :terms simply returns the value passed in to the model object from the params hash which will normally be "1" from a checkbox field.
In the case of someone has the same problem like me with devise, i add this answer:
i added to the devise's registration form:
sign_up.html.erb
<%= f.check_box :terms_of_service %>
user.rb
validates, :terms_of_service, acceptance: true
i forgot to add :terms_of_service inside my configured_permitted_parameters and devise ignored the checkbox state.
application_controller.rb
before_filter :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u| u.permit(:email, :password, :password_confirmation, :terms_of_service)}
end
The configure_permitted_parameters method is used by devise for know what params he should be save in addition of email and password.
I had to use this format:
validates :accpeted_terms, :acceptance => {:accept => true}
validates_acceptance_of :terms, :accept => true
I found Candland's answer above for validates acceptance to be correct in Rails 3.1. This is how I set up my Rails 3.1.3 app to record the acceptance to the database.
In the migration,
class AddTermsToAccount < ActiveRecord::Migration
def change
add_column :accounts, :terms_of_service, :boolean, :default => false
end
end
In the model,
attr_accessible :terms_of_service
validates :terms_of_service, :acceptance => {:accept => true}
In the form,
<%= f.check_box :terms_of_service %>
<%= f.label :terms_of_service %>
I have tried this from Angular JS and Rails 4. Angular send parameter with true value but rails did not recognize true.
It can receive an :accept option, which determines the value that will
be considered acceptance. It defaults to "1" and can be easily
changed.
So, I change into this:
class Person < ActiveRecord::Base
validates :terms_of_service, acceptance: { accept: true }
end
If you have default parameter is 1 or 0. Try to do this:
class Person < ActiveRecord::Base
validates :terms_of_service, acceptance: true
end
This is for more documentation. acceptance validation.
I hope this help you.
A call to a factory creates the record, so your subsequent calls to save are in fact updates, so your validation fails as intended. Try it without the factory and it should work.
if you have a basic checkbox in your view, such as
<%= builder.check_box :agreement %>
just put this line in your model
validates :agreement, :acceptance => true
which uses the default "1" generated by the check_box view helper

In Rails 3, how can I display the value of the error when using validation errors?

I want to display something like:
validates :field, :inclusion => { :in => fields, :message => "is not allowed: {self.field}"}
But the self is referring to the class itself rather than the instance variable.
If I understood it correctly, you want something like
class Coffee < ActiveRecord::Base
validates_inclusion_of :size, :in => %w(small medium large),
:message => "%{value} is not a valid size"
end
Example from the docs

How to update attributes without validation

I've got a model with its validations, and I found out that I can't update an attribute without validating the object before.
I already tried to add on => :create syntax at the end of each validation line, but I got the same results.
My announcement model have the following validations:
validates_presence_of :title
validates_presence_of :description
validates_presence_of :announcement_type_id
validate :validates_publication_date
validate :validates_start_date
validate :validates_start_end_dates
validate :validates_category
validate :validates_province
validates_length_of :title, :in => 6..255, :on => :save
validates_length_of :subtitle, :in => 0..255, :on => :save
validates_length_of :subtitle, :in => 0..255, :on => :save
validates_length_of :place, :in => 0..50, :on => :save
validates_numericality_of :vacants, :greater_than_or_equal_to => 0, :only_integer => true
validates_numericality_of :price, :greater_than_or_equal_to => 0, :only_integer => true
My rake task does the following:
task :announcements_expiration => :environment do
announcements = Announcement.expired
announcements.each do |a|
#Gets the user that owns the announcement
user = User.find(a.user_id)
puts a.title + '...'
a.state = 'deactivated'
if a.update_attributes(:state => a.state)
puts 'state changed to deactivated'
else
a.errors.each do |e|
puts e
end
end
end
This throws all the validation exceptions for that model, in the output.
Does anybody how to update an attribute without validating the model?
You can do something like:
object.attribute = value
object.save(:validate => false)
USE update_attribute instead of update_attributes
Updates a single attribute and saves the record without going through the normal validation procedure.
if a.update_attribute('state', a.state)
Note:- 'update_attribute' update only one attribute at a time from the code given in question i think it will work for you.
try using
#record.assign_attributes({ ... })
#record.save(validate: false)
works for me
Yo can use:
a.update_column :state, a.state
Check: http://apidock.com/rails/ActiveRecord/Persistence/update_column
Updates a single attribute of an object, without calling save.
All the validation from model are skipped when we use validate: false
user = User.new(....)
user.save(validate: false)
Shouldn't that be
validates_length_of :title, :in => 6..255, :on => :create
so it only works during create?

Resources