Rails – Healthy Migration Habbits – a repost

We are using a gem that encrypts database table columns. So far, it is working as intended, however, we encountered several issues where a column or a model attribute is missing, or simply not working. It turns out that we do migrations wrong.

Database Migration

Database migration is one of the features of any web application framework that allows developers to alter tables or data in a programmable and consistent manner. In Ruby on Rails, we sometimes write migrations that not only migrate table definitions, but also migrate data.

Data Migration

With data migration, it is common to use the model directly. However, the model and the database schema, most of the times, can be out of sync since the model is always the latest version and the schema may be a few migrations way from the latest. The result is that the migration will fail.

According to this guide – Healthy Migration Habbits – we should never reference the model directly.

Adjustments

Here is our model where we are trying to apply ssn with encryption. The attr_encrypted gem requires a column called encrypted_orig_column_name, in this case, the encrypted_ssn.

class User < ActiveRecord::Base
  attr_encrypted :ssn, encryptor: CustomEncryptor
end

Usually, we will write this migration file:

class UserEncryption < ActiveRecord::Migration[5.0]
  def up
    add_column :users, :encrypted_ssn, :text
    User.reset_column_information
    User.all.each do |node|
      node.update!(encrypted_ssn: User.encrypt_ssn(node.ssn))
    end
    remove_column :users, :ssn
  end

  def down
    add_column :users, :ssn, string, limit: 191
    User.reset_column_information
    User.all.each do |node|
      node.update!(ssn: User.decrypt_ssn(node.encrypted_ssn))
    end
    remove_column :users, :encrypted_ssn
  end
end

However, this might not work at all as our original ssn column is not yet encrypted, but the model already assumes it is encrypted. The proposed method is to create a bare ActiveRecord class so that it is free from interference from the original model.

class UserEncryption < ActiveRecord::Migration[5.0]
  class MigrateUser < ActiveRecord::Base
    self.table_name = :users
  end

  def up
    add_column :users, :encrypted_ssn, :text
    User.reset_column_information
    MigrateUser.all.each do |node|
      node.update!(encrypted_ssn: User.encrypt_ssn(node.ssn))
    end
    remove_column :users, :ssn
  end

  def down
    add_column :users, :ssn, string, limit: 191
    User.reset_column_information
    MigrateUser.all.each do |node|
      node.update!(ssn: User.decrypt_ssn(node.encrypted_ssn))
    end
    remove_column :users, :encrypted_ssn
  end
end

We will need the model functionality, ie: the ability to encrypt/decrypt. What we did is to access the column directly using the bare active record class so that attr_encrypted won’t get in the way.

See Healthy Migration Habits for more tips.

Posted in Rails | Tagged , | Leave a comment

Redirect All Requests to HTTPS with Nginx

Assuming that you already have a working HTTPS configuration for your website and you decided to redirect all requests to HTTPS, here is a simple nginx configuration for that. This assumes that you don’t want to serve HTTP anymore. This … Continue reading

Posted in Linux | Tagged | Leave a comment

Creating Self-Signed Certificate for Web Servers Like Nginx

I’m not sure if I have written this before, but here is how we create a self-signed certificate (without the passphrase) to be used by web servers like Apache or nginx. Gist – creating self-signed certificate. This one works for … Continue reading

Posted in Linux | Tagged , , | Leave a comment

Angular 4.x – Add a 404 page

For a frontend application like Angular, the 404 page is served by the frontend application rather than the web server. To make this work, we should always return the index.html of our angular application for all applications, except for asset … Continue reading

Posted in Angular | Tagged , , | Leave a comment

Angular 4.x and Beyond – Twitter Bootstrap Nav Bar Not Working in Mobile

Yesterday, I have deployed my personal site into production which is built with Angular 4.x using an old template (Twitter Bootstrap 2.x). I just recently noticed that the navigation menu is not expanding when viewed in smaller screens. It is … Continue reading

Posted in Angular | Tagged , | Leave a comment

Angular 4.x – Integrate a jQuery Plugin

I’m using a very old twitter bootstrap template which is using jQuery Colorbox plugin to handle image preview modal like lightbox did. It took me more or less 4 hours to figure it out given I’m fairly new to Angular … Continue reading

Posted in Angular | Tagged , | Leave a comment

Rails – Encrypting Database Columns with Key Rotation

Encryption is not an easy task. You have to manage the encryption itself, key rotation and securing the keys. In this post, I’ll describe how we managed to encrypt our database columns and enable key rotation as well. This post … Continue reading

Posted in Rails | Tagged , , , , | Leave a comment

AWS RDS In A VPC

For the past few days, I’m trying to replicate a setup in AWS where the database server access is secured in a private subnet while the web server is located in a public subnet. The documentation is pretty straightforward for … Continue reading

Posted in AWS | Tagged , , | Leave a comment

1Password button not working on Firefox

It’s been 2 weeks now my 1Password extension is not working on Firefox. The button is not clickable even after upgrading to the latest Firefox version. After asking help from 1Password on Twitter, it turns out that the fix is … Continue reading

Posted in Personal Blog | Tagged , | 1 Comment

Rails 5 – API Only – Enable Cookies and Sessions

So you’ve been trying a lot of trial and errors just to enable cookie based session on a API only rails app? Are you trying to customize the cookie expiration but it simply defaulting to default session only cookies? The … Continue reading

Posted in Ruby, Web Development | Tagged , | Leave a comment