One of my least-favorite Rails scenarios goes like this:
pry> user = User.find(id)
pry> user.bio = "a valid bio"
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
I pulled a record from the database, made a valid change, and was unable to save because the record I got from the database was invalid. This is especially frustrating when I make a larger change and scour hundreds of lines of intermedia code before I realize that User.find(id).save! would’ve failed just the same.
What’s happening here?
ActiveRecord has a number of useful methods that also skip your setters, validations, and callbacks. They’re fast and convenient, but make it easy to save invalid data or update existing data into an invalid state. Rather than being namespaced into a module or using a convention like “bang methods are unsafe”, most have names that are small variations on safe methods.
destroy is safe, delete is not. update and update! are both safe but update_column and update_columns are both unsafe. update_attributes is safe, update_attribute is not – wait, or do I have those the wrong way around?
There’s no structure, you’d have to memorize them, so I made a cheat sheet of the safe and unsafe methods on model classes and instances.
Here’s the PDF:
Most of the unsafe methods are useful for performance reasons, so I’m not saying to never use them. But I’d like to see them only used from a class or method that has “unsafe” in the name, put a big warning sign on them so that they don’t slip into normal use of your code.
I’ve got more ideas for locating and preventing persisted invalid data in the works for a RailsConf 2016 talk – join the mailing list below for early peeks at them.