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
Related
When I create a new form in ActiveAdmin, I want validations on my form input fields. But I can't find a related tutorial. I want some fields to accept only alphabets, some only digits , and some should be of specific length.
f.input :name, :label => "Title", input_html: { autofocus: true }
f.input :description
f.input :email
f.input :contact_number
f.input :contact_person
[Answer not only for ActiveAdmin, but for RoR in general]
You should do it in model.
• For digits only:
You want your :contact_number to be a digit, so your model (e.g. User) should look like this:
class User < ActiveRecord::Base
validates :contact_number, numericality: {only_integer: true}
end
• For min. 5 characters:
If description for example must be at least 5 characters it will be:
validates_length_of :description, minimum: 5
• For letters only:
validates_format_of :name, with: /^[-a-z]+$/
(details about reg. expressions --> Validate: Only letters, numbers and - )
Additional info:
If your form don't pass model validation it will return alert about wrong argument (which is accessible in flash[:alert] array).
More about it in:
http://guides.rubyonrails.org/active_record_basics.html#validations
You can have the validations defined in your corresponding Model class.
See the official documentation for Rails validation.
ActiveAdmin will pick it up when you try to create/edit/update objects of that model if you have Rails standard validations or even custom validations defined in your Model class.
For example, for your email validation, you can have this in your model:
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
Then, when you try to create/save an object through ActiveAdmin, it will show you error if the email is not in the correct format.
So, you have to define all of your validations (for all the fields that you want) in your model. That's it!
And, to display a list of all validation errors, you have to do:
form do |f|
f.semantic_errors *f.object.errors.keys
# ...
end
Update
Add these validations to your Model class:
validates_presence_of :description
validates_format_of :email, :with => /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
validates :contact_number, :presence => {:message => 'hello world, bad operation!'},
:numericality => true,
:length => { :minimum => 10, :maximum => 15 }
These are Rails standard validations. You can add custom validations to your model too.
For example, if you want to add a custom validation for the username, you can define that like this:
validate :username_must_be_valid
And, then define the custom validator method username_must_be_valid in the same model class like this:
private
def username_must_be_valid
errors.add(:username, 'must be present') if username.blank? && provider.blank?
end
I have this code in my user model:
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
attr_accessor :password
before_save :encrypt_password
validates :email, :presence => true,
:uniqueness => { :case_sensitive => false },
:format => { :with => /\A[^#]+#[^#]+\z/ },
:length => 7..128
validates :password, :presence => true,
:confirmation => true,
:length => 6..128
private
def encrypt_password
return unless password
self.encrypted_password = BCrypt::Password.create(password)
end
end
Now in my controller when I'm updating some user fields with
#user.update_attributes(params[:user])
the password field is always validated, even when it is not set in the params hash. I figured that this is happening because of the attr_accesor :password which always sets password = "" on update_attributes.
Now I could simply skip the validation of password if it is an empty string:
validates :password, :presence => true,
:confirmation => true,
:length => 6..128,
:if => "password.present?"
But this doesn't work because it allows a user to set an empty password.
Using update_attribute on the field I'd like to change is not a solution because i need validation on that attribute.
If I pass in the exact parameter with
#user.update_attributes(params[:user][:fieldname])
it doesn't solve the problem because it also triggers password validation.
Isn't there a way to prevent attr_accesor :password from always setting password = "" on update?
New answer
This works for me:
validates :password, :presence => true,
:confirmation => true,
:length => { :minimum => 6 },
:if => :password # only validate if password changed!
If I remember correctly it also took me some time to get this right (a lot of trial and error). I never had the time to find out exactly why this works (in contrast to :if => "password.present?").
Old answer - not really useful for your purpose (see comments)
I get around this problem by using a completely different action for password update (user#update_password). Now it is sufficient to only validate the password field
:on => [:create, :update_password]
(and also only make it accessible to those actions).
Here some more details:
in your routes:
resources :users do
member do
GET :edit_password # for the user#edit_password action
PUT :update_password # for the user#update_passwor action
end
end
in your UsersController:
def edit_password
# could be same content as #edit action, e.g.
#user = User.find(params[:id])
end
def update_password
# code to update password (and only password) here
end
In your edit_password view, you now have a form for only updating the password, very similar to your form in the edit view, but with :method => :put and :url => edit_password_user_path(#user)
The solution I have started using to get round this problem is this:
Start using ActiveModel's built in has_secure_password method.
At console
rails g migration add_password_digest_to_users password_digest:string
rake db:migrate
In your model:
class User < ActiveRecord::Base
has_secure_password
attr_accessible :login_name, :password, :password_confirmation
# secure_password.rb already checks for presence of :password_digest
# so we can assume that a password is present if that validation passes
# and thus, we don't need to explicitly check for presence of password
validates :password,
:length => { :minimum => 6 }, :if => :password_digest_changed?
# secure_password.rb also checks for confirmation of :password
# but we also have to check for presence of :password_confirmation
validates :password_confirmation,
:presence=>true, :if => :password_digest_changed?
end
And finally,
# In `config/locales/en.yml` make sure that errors on
# the password_digest field refer to "Password" as it's more human friendly
en:
hello: "Hello world"
activerecord:
attributes:
user:
password_digest: "Password"
Oh, one more thing: watch the railscast
I am using Ruby on Rails 3 and I would like to validate a single attribute for a submitting ActiveRecord instead of all its attributes.
For example, in my model I have:
validates :firstname, :presence => true, ...
validates :lastname, :presence => true, ...
I would like to run validation on the :firstname and on the :lastname separately. Is it possible? If so, how can I make that?
P.S.: I know that for validation purposes there are methods like "validates_presence_of", "validates_confirmation_of", ..., but I would like to use only the above code.
You can setup a virtual attribute on your model, and then do conditional validation depending on that attribute.
You can find a screencast about this at http://railscasts.com/episodes/41-conditional-validations
class Model < ActiveRecord::Base
def save(*attrs)
Model.validates :firstname, :presence => true if attrs.empty? || attrs.include?( :firstname )
Model.validates :lastname, :presence => true if attrs.empty? || attrs.include?( :lastname )
...
super
end
end
m = Model.new
m.save
#=> false
m.save(nil) # same as save(false), you can use both of them
#=> true
m = Model.new :firstname => "Putty"
m.save
#=> false
m.save(:firstname, :lastname)
#=> false
m.save(:firstname)
#=> true
You can just delete the second line of your code above so it reads:
validates :firstname, :presence => true
No validation will then be performed on the :lastname.
Regards
Robin
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.
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?