ColumnSync
Keeping in sync columns in different tables is a pretty common step during database refactorings. The
column_sync
gem provides ActiveRecord migration helpers to facilitate the sync of data between
columns.
Installation
Install the gem and add to the application's Gemfile by executing:
$ bundle add column_sync
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install column_sync
Usage
The following snippet should be used as a migration template:
class SyncColumns < ActiveRecord::Migration[7.1]
def up
sync_columns(Subscription => :country_code, Company => :country)
end
def down
unsync_columns(Subscription => :country_code, Company => :country)
end
end
The migration above generates the functions and triggers needed to keep subscriptions.country_code
in sync with companies.country
.
You also need to update your models to reflect the syncroniaztion between their columns:
class Company < ApplicationRecord
include ColumnSync::Model
has_one :subscription
sync_column :country, to: :subscription, column: :country_code
end
class Subscription < ApplicationRecord
include ColumnSync::Model
belongs_to :company
sync_column :country_code, to: :company, column: :country
end
Example
Given the following scenario:
Company.create!(country: "es")
Subscription.create!(country_code: "es", company: Company.first)
Changes are reflected in memory when the value is modified:
company = Company.first
company.country = "fr"
company.subscription.country_code
# => "fr"
company.subscription.country_code = "ca"
company.country
# => "ca"
Changes are also reflected in the DB when the value is persisted:
company = Company.first
company.update(country: "it")
company.subscription.country_code
# => "it"
company.subscription.update(country_code: "ma")
company.country
# => "ma"
Limitations
- Each
sync_columns
statement can only sync a pair of columns. If the same column needs to be synchronized across multiple tables, multiple such statements will be needed. - The gem expects a
has_one
-belongs_to
association between the models involved. It uses Rails reflections to understand the table names and column names involved. - It is assumed that the records are initially in sync, so it does not automatically sync values using any of the two columns involved.
- It also does not sync values when a row is created, only when it is modified.