1 min read

Tags

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 Image.

rails console
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 records.

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.name.gsub.

The image is not missing because we’re iterating through all the existing images using find_each. The name however is suspicious.

Let’s run an ActiveRecord query to see if a name is missing for any Image records.

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.