Timur Shtatland
Timur Shtatland

Reputation: 12377

Reusing code across multiple migrations: helper modules and helper methods

I need to reuse the same method across many migrations. My goal is to avoid code duplication. I tried to do it as shown below, by putting the shared method into file lib/migration_helper.rb and using include MigrationHelper in the migrations that use the shared method.

Is there a more standard way of sharing code in different migrations?

In particular, I put the helper file into lib directory - is this the correct place?

## lib/migration_helper.rb

# Methods shared across migrations.

module MigrationHelper
  def my_shared_method
    # some shared code
  end
end
## db/migrate/do_something.rb

class DoSomething < ActiveRecord::Migration[5.2]
  include MigrationHelper
  # rubocop:disable Metrics/MethodLength
  def up
    # some code
    my_shared_method
  end
  # rubocop:enable Metrics/MethodLength

  def down
    # more code
    my_shared_method
  end

SEE ALSO:

I got a few ideas from these questions, but they do not fully answer my question:
Custom helper methods for Rails 3.2 Migrations
Rails share code between migrations (aka concerns)
Accessing custom helper methods in rails 3 migrations

This repo has examples of a much more complex version of what I want, with a whole hierarchy of helpers. I need a simpler solution:
https://gitlab.com/gitlab-org/gitlab-foss/blob/master/lib/gitlab/database/migration_helpers.rb
https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/db/migrate/20220808133824_add_timestamps_to_project_statistics.rb

Upvotes: 6

Views: 611

Answers (1)

Nathan Gouy
Nathan Gouy

Reputation: 1422

just tested, works in rails 7 (and probably earlier version)

What you could do is:

1 - create your file/class kinda wherever

  • app/lib/migration/something.rb
  • db/concerns/something.rb
  • ...
# db/concerns/create_column_alias.rb
module CreateColumnAlias
  def create_column_alias(*args)
    add_column(*args)
  end
end

2 - create an initializer to inject your new helper in the migrations classes (per this gist)

# initializers/extend_migration_with_custom_helpers.rb

require_relative "../../db/concerns/create_column_alias"

ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, CreateColumnAlias)

3 - profit.

>$ bin/rails g my_migration

# db/migrate/123345456_my_migration.rb
class MyMigration < ActiveRecord::Migration[7.0]
  def change
    create_column_alias :tasks, :done, :boolean
  end
end

edit

In case you don't want them to be included everywhere, you can skip the serializer and do

require_relative "../concerns/create_column_alias"

# db/migrate/123345456_my_migration.rb
class MyMigration < ActiveRecord::Migration[7.0]
  include CreateColumnAlias

  def change
    create_column_alias :tasks, :done, :boolean
  end
end

Though I suggest you not to do that and save you the trouble. It's ok to have all your helpers available at any time even if you don't use them, especially given this has 0 impacts on production rapidity (only the deployment part, and it's super minimal like if you have 100 helpers you will lose only a few seconds)

Upvotes: 2

Related Questions