Sometimes I need to make changes to a Ruby on Rails table in production.
Before doing ANYTHING in production, I create a script and run the script in my local development environment.
If the table that you’re changing in production doesn’t have sensitive information, I suggest exporting the table into a CSV sheet as a backup in case something goes wrong.
I’ll ssh into the production server and run the rails console and check how many records I’ll be changing on the model
rails c Image.count # 40,000 records
I’ll run a script to take the name string and substitute underscores with spaces.
Note that I’m using the
find_each method instead of
each. We have a lot of records and
each will load all 40,000 records into memory. Things might crash.
find_each will load a batch of 1,000 records by default as it goes through all the
Image.find_each do |image| changed_name = image.name.gsub("_", " ") image.update_columns(name: changed_name) end
One minute into running the script, it returns an error:
NoMethodError: undefined method `gsub' for nil:NilClass from (irb):26:in `block in irb_binding' from (irb):25
It’s hard to debug in production console. The hint here is that
gsub was called on something that doesn’t exist.
In our script, we called
image is not missing because we’re iterating through all the existing images using
name however is suspicious.
Let’s run an ActiveRecord query to see if a name is missing for any
FreshStockAsset.where(name:nil).count # 5
There’s the problem! Five records are missing a name. I can go through them an give them a name and then re-run the original script. It should run without errors.
A long term solution to this is to think about whether there should be validation on the presence of a name for a saved image.