validates in rails - ruby-on-rails

I have a model with valid data; everything works.
In the form, I select as how to select the option I choose I want to be valid also 2 fields
validates_presence_of :is_ranking, :on => :update
validates :awards_count, :on => :update, :unless => :is_ranking == 1
Now as is_ranking == 1 to check again: awards_count
All sent from a form before being added to the database
How do I force rails to valid these two additional fields on the form I choose to rip options in select?

you should use symbol or string with :if and :unless
Try to replace condition with method
validates :awards_count, :on => :update, :unless => :is_ranking?
# You actually don't need that method in case your `is_ranking` field is `boolean`.
def is_ranking?
is_ranking == 1
end
Or with string
validates :awards_count, :on => :update, :unless => "is_ranking?"

Related

Validation fails on ":on => :save"

I am using rails 3.0.10 and ruby 1.9.2p0
In my rails app I am trying to validate my model through a "validates_uniqueness_of"
In my model(label) there is field named as "name" and I want to validate it as:
validates_uniqueness_of :name, :scope => [:portal_id], :on => :save
Portal is another model in my app.
It validates perfectly when i use :on => :create or :update individually, but fails when i use :on => :save
any idea I want to validate on save, but AR validation fails.
As default all validations run before save.so no need to give :on => :save
Simply use
validates_uniqueness_of :name, :scope => [:portal_id]

Validate attribute only if it present (only if user fill in it)

I need validate some attributes ONLY if they are not empty.
For example the user may have a logo. If we try to load it - validation should work. If we simply update the user's data without the logo, validation must be skipped.
Now i have:
The form has a choice of two files. One - logo, second - avatar.
Both of this attributes is part of User model. In User model a have validation:
validates_preference_of :logo_file_name, :message=>I18n.t("...")
validates_format_of :logo_file_name, :with=>/\.(jpeg|jpg|png|gif)$/i, :message=> I18n.t("...")
validates_preference_of :avatar_file_name, :message=>I18n.t("...")
validates_format_of :avatar_file_name, :with=>/\.(jpeg|jpg|png|gif)$/i, :message=> I18n.t("...")
In this case, if we try to create a new User without selected logo and avatar, we will have errors (our validation). I tryed change validation and add ":on => :update" like this:
validates_preference_of :logo_file_name, :message=>I18n.t("..."), :on => :update
validates_format_of :logo_file_name, :with=>/\.(jpeg|jpg|png|gif)$/i, :message=> I18n.t("..."), :on => :update
validates_preference_of :avatar_file_name, :message=>I18n.t("..."), :on => :update
validates_format_of :avatar_file_name, :with=>/\.(jpeg|jpg|png|gif)$/i, :message=> I18n.t("..."), :on => :update
Now i can create user without selected logo and avatar, but if i try edit user and try upload only logo - i have validation errors of avatar. If i choose file for avatar and logo leave blank - i have validation errors for logo.
How i can run validation ony for attribute that I want to change?
Add :allow_blank => true and it should do what you want.
Some validations accept the options :allow_blank => true or :allow_nil => true.
If this fails, use :if condition, like this:
validates_format_of :avatar_file_name,
:with=>/\.(jpeg|jpg|png|gif)$/i,
:message=> I18n.t("..."),
:on => :update,
:if => lambda{ |object| object.avatar_file_name.present? }
But i encourage you to use allows. Much cleaner.
Maybe :if => lambda {|attr| attr.present?} will help?

multiple validations based on action with rails

how can have different validations depending on the action?
validates :total_pressed,
:numericality => { :on => :create, :greater_than => 0 },
:numericality => { :on => :update, :greater_than_or_equal_to => 100 }
the first numericality statement is ignored
You can use validate_on_create and validate_on_update
def validate_on_create # is only run the first time a new object is saved
errors.add(:total_pressed, 'invalid number') if total_pressed < 0
end
def validate_on_update
errors.add(:total_pressed, 'invalid number') if total_pressed < 100
end
In you validate first numericality statement is ignored because it`s hash and one thing rewrite another
You can do this:
validates :total_pressed, :numericality => { :on => :create, :greater_than => 0 }
validates :total_pressed, :numericality => { :on => :update, :greater_than_or_equal_to => 100 }
Generally the validation operates on both create and update (via save), so if you pass the on flag then you'll limit it to either of the two methods. If you want to have different validation based on the action, then you're best off using a custom validation.
i.e
validate :total_pressed_on_create, :total_pressed_on_update
def total_pressed_on_create
errors.add(:total_pressed, 'invalid number') if self < 0 and self.new_record?
end
def total_pressed_on_update
errors.add(:total_pressed, 'invalid number') if self < 100 and !self.new_record?
end
Something along those lines. Check Rails Guide: Validation for more details.

ActiveRecord validation by parent attribute

I have model Article, for example. Article has_one ArticleContent. ArticleContent has validation of all it's attributes by default. But I need additional functionality - to save draft Article, without any validation.
So I pass :draft => false as one of a parameter in Article.new(), next I do #article.build_article_content(). There is some not working code in ArticleContent:
def draft?
raise self.article.draft
end
validates_presence_of :header, :message => "We have no fuckin' header!", :unless => :draft?
Of course it's not work. At the moment of draft? execution there is no any suitable Article object anywhere, so self.article returns nil. Nice try, codemonkey...
Anyone have some sweet ideas? I think to make #content.save! is not a very good idea
UPDATE
I tried so:
def draft
self[:draft]
end
def draft=(value)
self[:draft] = value
end
def draft?
self[:draft]
end
validates_presence_of :field1, :message => "msg1", :unless => :draft?
validates_presence_of :field2, :message => "msg2", :unless => :draft?
validates_presence_of :field3, :message => "msg3", :unless => :draft?
It works, but how can I group this?
unless self.draft?
validates_presence_of :field1, :message => "msg1"
validates_presence_of :field2, :message => "msg2"
validates_presence_of :field3, :message => "msg3"
end
Says that draft? method is not found. Also i should do
#article.content.draft = #article.draft
And it looks like dirty-dirty hack too
This is a common use case for a state machine. There are several rails plugins that provide for those.
http://ruby-toolbox.com/categories/state_machines.html
If you don't need a full state machine implementation it could still be instructive to have a state column in your ArticleContent model. Its values would be "new", "draft", "published" and so on. Your validations would look at that column's value when deciding what to do, like:
validates :content, :presence => true, :unless => Proc.new { |a| a.state == "Draft" }
(I'm pretty sure that's not the correct syntax but you should get what I'm aiming at.)
To answer your UPDATE
Try with_options.
with_options :unless => :draft? do |o|
o.validates_presence_of :field1, :message => "msg1"
o.validates_presence_of :field2, :message => "msg2"
o.validates_presence_of :field3, :message => "msg3"
end
Looking at your code there's a couple of smells. In order to flunk a validation the thing to do is errors.add(blah), not raise an exception. Also, your methods defined for accessing the draft column look a little redundant. They're just doing what AR would do anyway.

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