before_save not working with Rails 3 - ruby-on-rails

I have this Project model:
class Project < ActiveRecord::Base
validates :status, :inclusion => { :in => ['active', 'closed'] }
validates :title,
:presence => true,
:length => { :in => 4..30 }
before_save :set_default_status_if_not_specified
private
def set_default_status_if_not_specified
self.status = 'active' if self.status.blank?
end
end
If I create a new object like this:
Project.create!(:title => 'Test 2', :pm_id => 1)
I get these errors: Validation failed: Status is not included in the list
But status field should get filled in before save.

That's because it validates before before_save.
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
(-) save
(-) valid
(1) before_validation
(-) validate
(2) after_validation
(3) before_save
(4) before_create
(-) create
(5) after_create
(6) after_save
(7) after_commit
You could try before_validation ?

It looks like validation happen before the before_save callbacks. Perhaps you want to try before_validation instead?

Related

How not to allow validation for a specific action in Rails 4

I have this password validation in my user.model.rb:
class User < ActiveRecord::Base
validates :password, presence: true, confirmation: true,
format: {:with => /^(?=.*[0-9])(?=.*[A-Z])(?=.*[&%$##*])[a-zA-Z0-9&%$##*]{8,}$/,
:multiline => true, :message => I18n.t('invalid_password')}
end
I want this validation to be called in each and every method but not in my update action.
I have a users_controller.rb that has a create and update action. I want it to check in the create action but not in the update action.
I also have a password_resets_controller.rb in which I want it to check in both create and update actions but not in users_controller update action. I am using the authlogic gem. Both controllers use the same model.
Please guide me on how to do this. Thanks in advance.
validates :password, :presence => {:on => :create}
OR
##here new_user is a method that you can create and use condionally
## or validates_presence_of :password, :if => :new_user?
validates_presence_of :password, :unless => :new_user?
def new_user?
//your code
end
OR Using with_options
class User < ActiveRecord::Base
has_many :roles
# Normal Validations
validates_presence_of :password
with_options :if => :customer? do |customer|
customer.validates_presence_of :password
end
def customer?
roles.any? { |role| role.name == "customer" }
end
end
Probably the most close answer can be:
class User < ActiveRecord::Base
validates :password, presence: true, if: :not_persisted?
def not_persisted?
!self.persisted?
end
end
This code will actually trigger the validation only if the object is not persisted (on create)

How do I use an if statement in Rails validation?

I'm trying to create a validation statement that validates an object if service_area is present UNLESS service_area_radius==0
Here's the statement I created, which doesn't work:
validates :service_area, :presence => true, unless: "service_area_radius==0"
http://railscasts.com/episodes/41-conditional-validations
Like this:
validates_presence_of :password, :if => :should_validate_password?
validates_presence_of :country
validates_presence_of :state, :if => :in_us?
attr_accessor :updating_password
def in_us?
country == 'US'
end
def should_validate_password?
updating_password || new_record?
end
validates :service_area,
presence: {message: "Area Radius is missing."}, if: :radius_found?
private
def radius_found?
service_area_radius > 0
end
The validation for service_area will be executed if radius_found? returns true.
radius_found? will return true when the service_area_radius(attribute) hold value > 0.
Adding a custom message with message: option, when the validation fails.

Rails - How to add validation on callback

I need to add validation on a before_validation model filter. How can I do that?
Thanks in advance
--
EDIT
I didn't express myself correctly. I need to add validation on a callback like that:
validate :check_length
def check_length
if my_conditional
validates_length_of :name, :minimum => 5
else
validates_length_of :name, :minimum => 7
end
You will have to create a method and call it from the callback
before_validation :run_this_check
def run_this_check
##run your validation
errors.add(:key, "This is your error message")
end
or if the validation is not dealing with an attribute (or field)
def run_this_check
errors.add_to_base('error message')
end
try using
class X < ActiveRecord
validates_length_of :name, :minimum => 5 if my_condition
validates_length_of :name, :minimum => 7 unless my_condition
end
what's the condition?

Using after_validation with an if or clause

Can someone please point me to the right direction.
I'm using after_validation to compete geocoding and I wanted to know how I can tact on an or || option to an if clause.
This works as intended
class Address < ActiveRecord::Base
after_validation :geocode, if: :address_changed?
But this doesn't
class Address < ActiveRecord::Base
after_validation :geocode, if: :address_changed? || :zipcode_changed?
Thanks in advance.
If you don't want to use Thilo's Proc approach then you can add your own custom method and use that:
class Address < ActiveRecord::Base
after_validation :geocode, if: :address_or_zip_changed?
private
def address_or_zip_changed?
address_changed? || zipcode_changed?
end
end
This may (or may not) read better and is handy if you need the same compound condition on multiple validations.
:if - Specifies a method, proc or string to call to determine if the validation should occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The method, proc or string should return or evaluate to a true or false value.
So try a proc:
if: Proc.new { |a| a.address_changed? || a.zipcode_changed? }
You can do this using :if
validates :email, :unique=> true, :if => Proc.new { email.present? }
or you could also use lambda
validates :email, :unique=> true, :if => lambda { email.present? }

Why aren't my before_validation methods firing if some validation is scoped?

In my model I've got a couple of methods to populate attributes of an Invoice before it is validated:
validates :account_id, :presence => true
validates :account_address, :presence => true
validates :number, :presence => true
validates :number, :uniqueness => true, :scope => :client_id
before_validation :generate_number, :associate_addresses, :on => :create
def generate_number
self.number = self.client.invoices.count + 1
end
def associate_addresses
self.account_address = self.account.addresses.first
end
And in the controller:
#invoice = #account.invoices.build(:client_id => #client.id)
if #invoice.save
#it saved
end
My problem is that the associate_addresses and generate_number methods only fire if I remove the :scope => :client_id argument on the :number validation.
Why would it skip the before_validation callbacks due to this?
Working in Rails 3.0.3
Thanks!
Thanks.
Don't know why it's skipping the before_validation methods, but to scope a uniqueness validation in Rails 3 you should use the following syntax:
validates :number, :presence => true, :uniqueness => { :scope => :client_id }
I guess that your syntax is making it try to add a scope validation, which doesn't exist. Probably there's a Rails bug that makes that skip the before_validation methods.

Resources