I want to validate that my field is from an especific class.
Concrete example. I have a model that must by unique by day. So, I insert a validation
validates :my_date_field, uniqueness: {scope: [:scope_one, :scope_two]}
If I create my record with a Date, the validation works fine. If I create my record with a Time, however, (my tests use Time::now) it parses it to a Date, but does not trigger the validation.
How should I fix it?
Thanks in advance.
--Edit--
A related problem:
How I forbid someone to do
MyModel::create my_date_field: 4
? It is passing the validate_presence from active_record, passing the null: false from migration, and saving an ugly 4 in my date_field.
I'm completely lost here =\
ActiveRecord will type-cast your values to whatever type it thinks is appropriate for the underlying database field. You can still access the original type, though, via my_date_field_before_type_cast. The *_before_type_cast accessors exist for every attribute. There you can check the class or do any other conversions you might need. These are available in custom validation methods as well.
Related
I am not sure if I understand totally active record validation role.
Of course, if a user inputs data (like an email or a country), I can and should validate its existence, its uniqueness or its inclusion in a list of countries
But for example, if I have methods in the backend that change an attribute page_clicked or click_date or even the column update_at, that I "control" i.e 'is not generated by a user's input', should I use active record validations ?
I'm asking this because on a very 'hot database' (need speed for millions of frequent updates), I wonder if checking on each update that updated_at is a datetime, and that if a clicked column is true/false and nothing esle is really necessary as the user is not the one inputting/controlling these data but I am through Rails custom methods I wrote
Thanks
I don't think there is a general satisfying answer to your question. It's up to you to enforce validation or not.
Remember that you don't have to use ActiveRecord for validation, you can also use your DBMS to ensure that:
a value will never be NULL (one of the most annoying errors)
a value has the correct TYPE
a FOREIGN KEY always points to an existing row in another table
and depending on your DBMS, a lot more is possible
If you need high INSERT speed and want to go with raw SQL INSERTS, putting some validation in your database can prevent nasty application errors later.
Validations should guard your database and its job should be to stop saving the records that are considered invalid by your application.
There is no hard rule on what is valid record you have to decide it your self by adding the validations. If the record wont pass the validation step it is simply not going to be saved to the database.
From Active Record Callbacks:
3.1 Creating an Object
before_validation
after_validation
before_save
around_save
before_create
around_create
after_create
after_save
after_commit/after_rollback
3.2 Updating an Object
before_validation
after_validation
before_save
around_save
before_update
around_update
after_update
after_save
after_commit/after_rollback
You can see that validation hooks run at the beginning of the object life cycle.
So in your case instead of asking your self a question:
Should I use active record validations if the record is not generated by a user's input.
You should ask your self:
Is this record invalid without page_clicked or click_date(aka them being nil)
UPDATE
If you consider record to be invalid but worrying about speed problems with running validations I would do the validations to make sure that all the records in the database are valid and try to find the way to optimise the speed somewhere else. Plus not 100% sure but time spend on saving invalid records and filtering them later on will be probably much longer then validating in the first place.
When performance is really a priority and that I am sure that we developers / the server are the only ones who can manipulate specific attributes of a Model, I will
Make sure that I create a separate method / wrapper method for this specific action.
In this specific method, I call .save (validate: false) instead of the usual .save
I still write validations for the said attributes for developers' reference to prevent future development errors, and in case a new developer comes in and accidentally save an invalid record, precisely just because there's no validation to safeguard it.
Or, I will use .update_column instead of .save (validate: false) to perform a direct DB call, skipping Model validations and callbacks (If you also do not want callbacks to be called).
Note that .update_column is different from .update.
I have a form and want the form input values to be check. If the values pass the check, then values can be stored in DB. I know I can check them in view, controller, or even model. I think probably the best way is to check them in all the three parts, and only check them in view before submit could cause problem because others can manually modify and send the request to the controller.
So for example, I have user variable in view. I don't want date type attribute user.start_date to be modify to be earlier than user.apply_date, how should I make the protection robust?
What you're looking for are model validations: http://guides.rubyonrails.org/active_record_validations.html
Check out the date_validator gem (https://github.com/codegram/date_validator)
It allows for validations like this:
validates :start_date, date: { after: :apply_date }
Doing it in the model, as that's the usual way. Ruby on Rails supports model errors extensively, and if there's an error you can simply redisplay the record and the errors in that record.
There are standard validations you can do to ensure a value is present, is unique, etc.
You can also do custom validations in the model
validate :start_date_cannot_be_before_apply_date
def start_date_cannot_be_before_apply_date
if start_date < apply_date
errors.add(:start_date, "can't be before the apply date")
end
end
I have a table with a column (dose) that is defined as a decimal. When the user fills out the form field for this column I want to make sure they enter a valid number. I want to use validates_numericality_of :dose but this doesn't work. If the user enters a non-numeric value (e.g. 'horse') a value of 0 is saved to the database and the validation is passed. I would prefer an error was raised.
Is there a way of catching this earlier in the object lifecycle? At what point is active record converting the string to a 0?
My expectation would be that you have another plugin or hook or something that's getting in the way and changing the value before validation.
To maybe get some more insight as to what the situation is, add a before_validation hook to the model and raise self.inspect to see what the object looks like right before the validations fire. Try to save an instance with text in the :dose attribute and see what it looks like.
I have a model called Contacts.
Contacts can have different status "bad, positive, wrong..."
These status may need to be changed over time, but across all contacts, they are the same options.
Should I model it this way:
Contacts.rb
belongs_to :status_contact
StatusContacts.rb
has_many :contacts
Then I manually populate the types of status in the table?
I then want to use Ajax to click a button corresponding to a value to update the value for Contacts.
It looks like you're trying to ensure that the values for your status are always going to restricted to a set of possible answers of your choosing. If that's all you're trying to do, there's no special need for a separate table. You can use the magic of ActiveRecord validations instead here.
First, create a string database column for Contact called :status.
Then you can use a validation to ensure that the values are limited to the ones you want. In Rails 3, you can do it like this:
validate :status, :inclusion => { :in => %w( bad positive wrong ) }
(If you're using Rails 2, use #validates_inclusion_of instead.)
In ActiveRecord, validations check that the object's values are valid before saving; it refuses to persist the object into the database until all validations pass.
Your naming strikes me as a little weird—ContactStatus sounds a little nicer to me—but I see this as being the general idea to achieve what you want.
No clear answer yet --- I think I need to use the table because it would allow the users to add and modify the types of status used across their application.
Given a model that has validations in the model_name.rb file, how can I access those validations manually? I'd like to cook up my own form validation system that would work alongside the built-in Rails tricks and I want to keep everything as DRY as possible. My main problem is that I need to make server-side validations before any of the form values hit the database (I'm using a multistep form).
Basically I'm wondering if there is a method like
User.validations.each do |v|
puts v.constraint.to_s + " " + v.message
end
Is there anything similar to this?
Thanks in advance.
My main problem is that I need to make
server-side validations before any of
the form values hit the database (I'm
using a multistep form).
If your model is not valid according to the validations in its class file, then its data won't get saved to the database (unless you pass false to the save method to suppress validations).
You can ask a model if it's valid at any point by invoking its valid?/invalid? methods.
The ActiveRecord object exposes the errors method after valid? is called, which gives you messages about which validations are violated. You could check valid? and then check to see if any of the fields on the part of the form you are on are invalid.
you could do something like this for a form with fields field1 and field2.
unless x.valid?
[:field1,:field2].each do |field|
yes_there_was_an_error if x.errors[field]
end
end
Your best bet is to use a state machine and store the data in the database between the various steps in the form.
You can do e.g. validates_presence_of :username, :if => proc {|u| u.signup_step >= 2 }, where signup_step is an integer column in the database.
So, even though you say you don't want to store it in the database between the forms, I think you should. If you do this, you can use regular validations and models, without nasty hacks. And honestly, I doubt doing it this way is a problem.