Skip to content

Add new Rails/MigrationExecute cop#1589

Open
a-lavis wants to merge 1 commit intorubocop:masterfrom
a-lavis:add-rails-migration-connection-execute-cop
Open

Add new Rails/MigrationExecute cop#1589
a-lavis wants to merge 1 commit intorubocop:masterfrom
a-lavis:add-rails-migration-connection-execute-cop

Conversation

@a-lavis
Copy link
Copy Markdown

@a-lavis a-lavis commented Feb 18, 2026

Adds a new cop I've titled Rails/MigrationExecute (but feel free to suggest a better name!).

This cop autocorrects connection.execute to simply execute in migrations.

I think this cop should exist because execute gives useful terminal output while the migration is running, whereas connection.execute does not.

Corresponding Rails Style Guide PR: rubocop/rails-style-guide#376

Let me know if I should create a corresponding issue on this repo!


Before submitting the PR make sure the following are checked:

  • The PR relates to only one subject with a clear title and description in grammatically correct, complete sentences.
  • Wrote good commit messages.
  • Commit message starts with [Fix #issue-number] (if the related issue exists).
  • Feature branch is up-to-date with master (if not - rebase it).
  • Squashed related commits together.
  • Added tests.
  • Ran bundle exec rake default. It executes all tests and runs RuboCop on its own code.
  • Added an entry (file) to the changelog folder named {change_type}_{change_description}.md if the new code introduces user-observable changes. See changelog entry format for details.
  • If this is a new cop, consider making a corresponding update to the Rails Style Guide.

@a-lavis a-lavis marked this pull request as draft February 18, 2026 15:29
@a-lavis a-lavis force-pushed the add-rails-migration-connection-execute-cop branch from f4fa7c3 to e736031 Compare February 18, 2026 15:49
@a-lavis a-lavis force-pushed the add-rails-migration-connection-execute-cop branch from e736031 to 65ab102 Compare February 18, 2026 15:53
@a-lavis a-lavis marked this pull request as ready for review February 18, 2026 15:54
@a-lavis a-lavis changed the title Add new Rails/MigrationExecute cop Add new Rails/MigrationExecute cop Feb 18, 2026
@pirj
Copy link
Copy Markdown
Member

pirj commented Feb 20, 2026

execute gives useful terminal output while the migration is running

Can you please give an example output?

@a-lavis
Copy link
Copy Markdown
Author

a-lavis commented Feb 21, 2026

Can you please give an example output?

For the migration:

class AddNicknameToUsers < ActiveRecord::Migration[8.1]
  def up
    execute <<~SQL.squish
      ALTER TABLE users
        ALGORITHM=INSTANT,
        ADD COLUMN nickname VARCHAR(255) NOT NULL DEFAULT '' AFTER email_address;
    SQL
  end

  def down
    execute <<~SQL.squish
      ALTER TABLE users
        ALGORITHM=INSTANT,
        DROP COLUMN nickname;
    SQL
  end
end

When running bin/rails db:migrate, you'll see:

== 20260221032541 AddNicknameToUsers: migrating ===============================
-- execute("ALTER TABLE users ALGORITHM=INSTANT, ADD COLUMN nickname VARCHAR(255) NOT NULL DEFAULT '' AFTER email_address;")
   -> 0.0115s
== 20260221032541 AddNicknameToUsers: migrated (0.0116s) ======================

On the other hand, if you use connection.execute instead, like so:

class AddNicknameToUsers < ActiveRecord::Migration[8.1]
  def up
    connection.execute <<~SQL.squish
      ALTER TABLE users
        ALGORITHM=INSTANT,
        ADD COLUMN nickname VARCHAR(255) NOT NULL DEFAULT '' AFTER email_address;
    SQL
  end

  def down
    connection.execute <<~SQL.squish
      ALTER TABLE users
        ALGORITHM=INSTANT,
        DROP COLUMN nickname;
    SQL
  end
end

then you'll instead only see:

== 20260221032541 AddNicknameToUsers: migrating ===============================
== 20260221032541 AddNicknameToUsers: migrated (0.0158s) ======================

As you can see, by using execute you get to see what SQL was executed and how long it took.
This becomes even more useful if you're doing multiple execute statements in one migration. Some examples of when you might want to do that:

  • When you want to use the INSTANT algorithm to add a column, and then use the INPLACE algorithm to add an index on that column.
  • When you want to use the INPLACE algorithm to add a foreign key constraint, so you need to disable foreign key checks temporarily for the migration with execute('SET SESSION foreign_key_checks = 0') before and execute('SET SESSION foreign_key_checks = 1') after.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants