Opinion: Validate Both Association And Id
I’ve beef with some of the validation recommendations out there.
Disagreeable Ideas
belongs_to
validation strategy espoused in this article.
I strongly disagree with:
Use association name for presence validator. (as opposed to :association_id)
My Recommendation
I will be mirroring a notion expressed here, namely
Think about Rails validations as purely something for user experience.
Think about database constraints as just being about data integrity.
To me it is essential that I never get database errors. In my opinion, correct application code should handle 99.99% of validation errors.
I have a threefold recommendation. With these three layers in place your app will be nigh-impenetrable to bad data while providing actionable validation errors transparent to both users and developers.
1. Use Database-level constraints
This is simple redundancy that will spare you a lot of headache.
All records in your relational database should always be valid, period.
Define your model migrations with appropriate :null
, :default
, :index
, and :unique
options!
Define sensible default values that match the field type!
t.references :user, null: false, unique: true, index: true # this works well when the parent object is not optional (a pure belongs_to), and the parent can have only one child.
t.integer :some_count, null: false, default: 0 # all number fields should disallow nulls and have a sensible default value!
t.text :some_text, null: false, default: ""
t.text :email, null: false, unique: true, index: true
2. Use Application-level validations on foreign keys
This mirrors the references field in DB-level validation, yes, but serves to provide error messages.
validates :user_id,
presence: true
3. Use Application-level validations on associations
This may seem redundant when the user_id
foreign key already gets validated, but will save you when record’s :user_id
is present, but the associated object has vanished.
validates :user,
presence: true