

Back in February I wrote about Sharing ActiveRecord models between different projects using ActiveRecord by using a combination of Rails and Scenic.
Well, what happens when you need to change the column type of one of the tables used by a Materialized View. How do you do that? Using the example I already have on github, and assuming you want to change products.name from string
to text
, you would need generate a migration:
rails g migration change_products_name
With the following content:
class ChangeProductsName < ActiveRecord::Migration
def up
drop_view :expensive_products, materialized: true
change_column :products, :name, :text
create_view :expensive_products, materialized: true
# If we had more versions for this materialized we would use the latest
# generated instruction, something like:
#
# update_view :expensive_products, version: 2, revert_to_version: 1, materialized: true
add_index :expensive_products, :id, unique: true
end
def down
drop_view :expensive_products, materialized: true
change_column :products, :name, :string
create_view :expensive_products, materialized: true
# Similar to "#up" we would do the same:
#
# update_view :expensive_products, version: 2, revert_to_version: 1, materialized: true
add_index :expensive_products, :id, unique: true
end
end
What is important to take from the code in this migration is how we make the change to update the table and then, after that, we create or update the materialized view, depending on how many versions we already have.
The important question about all of this is: Is this the right way to do it? This is definitely the way to do it if you don’t really have live traffic, or you don’t mind getting errors while the database is making the changes.
When your system has a lot of traffic you need to be careful and treat your clients with respect, to me the best way to handle a change like this is by doing the following:
I know all the steps above seem like overkill, but the truth is that if you’re trying to keep your system 100% uptime, with practically zero amount of errors and number of user complaints, that’s the only way to do it, basically: