Skip to content
This repository was archived by the owner on May 17, 2026. It is now read-only.

HykuAddons: Database migrations

Paul Danelli edited this page Feb 18, 2022 · 1 revision

Development

Migrations for database changes introduced by this engine are defined in db/migrate like any Rails application. These get copied into Hyku during installation when the following in run:

bundle exec rails app:hyku_addons:install:migrations

These files are suffixed by the engine name for easy identification (e.g. 20200103172822_add_contact_email_to_sites.hyku_additions.rb). This command is safe to rerun and will only copy over missing migrations. See https://edgeguides.rubyonrails.org/engines.html#engine-setup for more details.

To perform the migration you will need to scope the command as follows:

bundle exec rails db:migrate SCOPE=hyku_addons

Don't forget to run the test migations at the same time:

RAILS_ENV=test bundle exec rails db:migrate

Production - Ubiquity Press specific

Database migrations in production are not currently automatically run when the application is deployed - although this is a feature that should be added.

Because of the current way that migrations are handled it is necessary to deploy your changes, then log into your production environment, manually run db:migrate.

Log into your production environment, which for Google Cloud would be:

kubectl get pods | grep hyku

kubectl exec -it hyku-pod-name -- /bin/bash

bundle exec rails db:migrate

Adding Migrations

When writing migration they must use the up/down syntax and check if a table has already been created. This is because migrations might be installed more than one in development, or when tenants are added in production, their migrations need to be run after the initial migration may have been executed. Checking at a per line level in the migration also assists when re-running a failed migration manually.

# Example of how to check if a table currently exists
class CreateAccountCrossSearches < ActiveRecord::Migration[5.2]
  def self.up
    return if table_exists?(:account_cross_searches)

    create_table :account_cross_searches do |t|
      t.references :search_account, foreign_key: { to_table: :accounts }
      t.references :full_account, foreign_key: { to_table: :accounts }

      t.timestamps
    end
  end

  def self.down
    drop_table(:account_cross_searches)
  end
end

When adding columns you must follow the same pattern. Note that when adding indicies or foreign keys they must be added after column creation, and removed before the columns are removed:

class AddDisplayProfileToUsers < ActiveRecord::Migration[5.2]
  def self.up
    add_column      :users, :display_name, :string      unless column_exists?(:users, :display_name)
    add_index       :users, :display_name, unique: true unless index_exists?(:users, :display_name, unique: true)
    add_column      :users, :jobtitle_id, :integer      unless column_exists?(:users, :jobtitle_id)
    add_foreign_key :users, :jobtitles                  unless foreign_key_exists?(:users, :jobtitles)
  end

  def self.down
    remove_foreign_key :users, :jobtitles    if foreign_key_exists?(:users, :jobtitles)
    remove_index       :users, :display_name if index_exists?(:users, :display_name, unique: true)
    remove_column      :users, :display_name if column_exists?(:users, :display_name)
    remove_column      :users, :jobtitle_id  if column_exists?(:users, :jobtitle_id)
  end
end

Also note that when checking the existence of an index or foreign key you must correctly specify options such as unique for ActiveRecord to return a match.

Clone this wiki locally