Rails: Validation in Model VS Migration

Rails: Validation in model vs migration

Wherever possible, validate at the database level as well as at the model level.

Why? For starters, active record does not enforce validation in all contexts. The following methods skip validations, and will save the object to the database regardless of its validity:

decrement!
decrement_counter
increment!
increment_counter
toggle!
touch
update_all
update_attribute
update_column
update_counters

If you pass :validate => false to save, it will also skip validation. See the Active Record Validations and Callbacks Guide section on Skipping Validations for details. (If this worries you, there is even a gem for disabling these methods.)

So reason #1 is that Rails validations are not full-proof by any means: relying on them exclusively is risky, particularly for mission-critical validations such as uniqueness.

Speaking of which, reason #2 (off the top of my head): activerecord validations are prone to race conditions, and Rails' uniqueness validator in particular cannot guarantee uniqueness. Here's one article among many that documents why this is so.

Although they may be a rare occurrence, violations of uniqueness constraints can corrupt an entire data set. In the rare case that Rails is about to do this, you want at all costs to stop it, which is where the DB uniqueness constraint comes in: databases are built to handle this situation and will enforce uniqueness consistently, even when Rails does not.

And reason #3: why not validate both in the model and in the DB? Sure, you duplicate a bit, but that's generally a pretty minor concern compared with the payoff if Rails misses something like a uniqueness validation check. This is really not an either/or proposition: it's always better to duplicate validation in the DB wherever you can, particularly for mission-critical constraints such as uniqueness.

Anyway, those are my thoughts, hope that helps.

Ref: Where Correctness Is Enforced (screencast by Gary Bernhardt, need subscription to view)

Model Validation from Migration - Ruby on Rails

It's unlikely that there's something out of the box in Rails.

But I've found a gem schema_validations which probably does, what you're looking for.

The only difference is that this gem follows DRY approach and doesn't generate validations in the model. For example, you have users table:

create_table :users do |t|
t.string :email, null: false, limit: 30
t.boolean :confirmed, null: false
end

This gem won't generate validations as you expect:

class User < ActiveRecord::Base
validates :email, presence: true, length: { maximum: 30 }
validates :confirmed, presence: true, inclusion: { in: [true, false] }
end

You're still going to have clean User model, but the fields are validated:

class User < ActiveRecord::Base
end

And it can be configured if you don't need validations on every model.

Ruby on Rails: How to migrate changes after adding validation on models?

Records already in your database won't be affected. But it you edit a previous record, you won't be able to store it without passing the validation.

You've 3 options:

  • On edit/update, force new field value (default in your case)
  • Create a migration to set default value on the column.
  • Create a migration to update each row with a correct value (not really a good option in my mind)

Ruby on Rails: Is it better to validate in the model or the database?

I would highly recommend doing it in both places. Doing it in the model saves you a database query (possibly across the network) that will essentially error out, and doing it in the database guarantees data consistency.

Validations in Rails

As is so often the case: it depends.

In a simple Rails application, all models will be updated through a view request to a controller which in turn fills in the params into the models, then tries to save the model and any validation errors that occur are rendered back to the server.
In that scenario, all your code will have to do is to react to failed calls to #save but you can sleep soundly knowing that everything in your database is how it is supposed to be.

In more complex applications, putting all the validation logic into your model might not work as well anymore: every call to #save will have to run through all the validation logic, slowing things down, and different parts of your application might have different requirements to the input parameters.

In that scenario there are many ways to go about it. Form objects with validations specific to the forms they represent are a very common solution. These form models then distribute their input among one or more underlying ActiveRecord models.

But the Rails way is to take these one step at a time and avoid premature optimization. For the foreseeable future, putting your validation into your model will be enough to guarantee consistency.

How to add validation in migration file (Rails 4)

Rails does let you provide null and default options to columns in migrations.

After editing the user migration file, have you rerun it?

You can do a rake db:rollback followed by a rake db:migrate

If you had run CreateUsers and AddIndexToUsersEmailAndUsername for last, You should do a rollback with two steps like rake db:rollback STEP=2

Presence:true vs. null:false in migration table

I guess it depends on what database you use and which keywords it supports.
So if a db that you use supports keyword 'presence:true', you can use it.

However the best practice is to use null:false, I've never seen anything other.

Plus, Rails has a special migration method for this case, and it's called change_column_null http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/change_column_null

Hope it's useful for you.

Rails model validators break earlier migrations

The easiest way to avoid this issue is to use rake db:schema:load on the second machine, instead of db:migrate. rake db:schema:load uses schema.rb to load the most current version of your schema, as opposed to migrating it up form scratch.

If you run into this issue when deploying to a production machine (where preserving data is important), you'll probably have to consolidate your migrations into a single file without conflicts.



Related Topics



Leave a reply



Submit