I am new to Ruby on Rails I have a scenario in which I have a form which has some fields. One of the field values I need to validate against a table which has the data . I want to restrict the user from saving any data unless the field is validated with the table records.
Initially I added the code in controller to validate that but I have other fields which I need to validate as empty so it did not work .
Also I want the the validation error to be part of other errors.
I tried the below code in the model file
before_create :validate_company_id
def validate_company_id
cp = Company.find_by_company_id(self.company)
if @cp != nil
return
else
self.status ||= "Invalid"
end
end
But its not validating , could you help me how I can validate it .
regards Surjan
The guys answered correctly, but provided the other way for solution. You could ask yourself: "Why doesn't my code get executed?"
First of all, you have errors in your code - @cp
is undefined. Also, I don't know what are you trying to achieve with self.status ||= "Invalid"
.
You also don't have to use self
when you're calling an attribute, but you do have to call it when you're assignig a new attribute value. So self.company
is unnecessary, you can just use company
.
I've also noticed you have the company_id
attribute in your companies
table. That's not neccessary, common convention is using just an id instead. If you don't want to alter your table you can set the id
field on your model like so:
class Company < ActiveRecord::Base
set_primary_key :company_id
# ... the rest of your model code ...
end
After that you can use Company.find
instead of Company.find_by_company_id
.
Okay, let's say you have the following code after the fixes:
before_create :validate_company_id
def validate_company_id
cp = Company.find(company)
if cp != nil
return
else
self.status ||= "Invalid"
end
end
First of all I would like to use ternary operator here
before_create :validate_company_id
def validate_company_id
Company.find(company) ? return : self.status ||= "Invalid"
end
Isn't this cleaner? It does the exact same thing.
Now about that self.status
of yours. If you would like to invalidate the object in ActiveModel
you have to set some values in errors
hash. You're in misconception if you think that a model with the status attribute of "Invalid" is invalid. It's still perfectly valid model in Rails.
So how do you invalidate?
You put some values into errors
hash. You can also specify a message and the attribute you're validation error refers to.
So let's do it on your model
before_create :validate_company_id
def validate_company_id
Company.find(company) ? return : errors.add(:company,"Invalid Company ID")
end
Now if you try to save your model with invalid company_id it will still pass and get saved to the DB. Why is that?
It's because of the ActiveModel
s lifecycle. Your method gets called too late.
Here are all the callback methods you can use
before_validation
after_validation
before_save
around_save
before_create
around_create
after_create
after_save
before_validation
after_validation
before_save
around_save
before_update
around_update
after_update
after_save
before_destroy
around_destroy
after_destroy
Notice how your method gets called long after the validation cycle. So you should not use before_create
, but after_validation
or before_validation
callbacks instead.
And here we are with the working validation method of your model.
after_validation :validate_company_id
def validate_company_id
Company.find(company) ? return : errors.add(:company,"Invalid Company ID")
end