Five Practices for Robust Ruby on Rails Applications
Whenever I come across a rails application with inconsistent data or bugs that are hard to nail down I tell myself: “They (the developers) were just a couple of keystokes away from preventing those issues from happening”.
At Brewhouse, we follow five simple practices to make our Rails applications robust. It all comes down to failing early, loudly and often. We ensure that data is valid and applications behave properly by catching issues early on.
Hash#fetch to catch malformed hash
unexpected method 'upcase' for nil… Whenever you expect a Hash to contain a key, prefer
fetch() will raise an error when the key is missing so you won’t
nil values around and see unrelated errors happening down the
case ... else raise to catch invalid data
Always add an
else raise ... clause to your
case statements. You
want to know when you’ve received an unexpected value rather than
ignoring it and moving on.
! methods to fail loudly
Data is often being seen as the most valuable asset in a company. Failing silently to persist data can have a huge impact then.
Whenever you’re not expecting an operation to fail, use the “bang”
destroy! that raise exceptions on
failure. This extra key stroke
will save you from dealing with inconsistent data.
Used in test code, it ensures that the setup doesn’t fail silently… there is nothing worse than a test that passes because the setup was incorrect.
Also, always wrap multiple calls into an SQL transaction to prevent your data from getting into an in-between state.
Add ActiveRecord validations to perform live checks
Pairing ActiveRecord validations with the use of ‘bang methods’ is a great way to ensure you persist valid data. For example:
Use database constraints to ensure data consistency
Your database is your best friend when it comes to ensuring data is present, not duplicated and that orphans are not left in the database.
Given the fact that the large majority of columns are required in a database, you should define columns with
null: false by default.
index ... unique: true
Did you know that rails
has_one does not prevent duplicate
associations from being created?
The best way to prevent this from making data inconsistent is to add a unique index.
The database will throw an error if you attempt to persist a duplicate record.
You don’t want orphan records in your database, do you?
Foreign keys help such things from happening. I’d recommend using the ruby gem schema_auto_foreign_keys to automatically add foreign keys on your behalf.
A few extra keystrokes goes a long way
A few extra keystrokes here and there can save you from hours of
debugging or recovering from inconsistent data. Use
validate and database constraints. Your coworkers and future-self
will thank you.
As always, feedback is greatly appreciated. I’d be happy to hear of any other practices I didn’t cover here.