This GitHub Action ensures that all foreign key columns in your Rails application have corresponding database indexes. It checks your schema.rb
to catch cases where foreign keys might be created or modified across multiple migrations.
Foreign keys without indexes can cause significant performance issues:
- Slow JOIN operations
- Poor query performance on foreign key lookups
- Potential table scans instead of index scans
Detects foreign keys defined in various ways:
# Direct column definitions
t.bigint :company_id
t.integer :user_id
# Rails associations
t.references :organization
t.belongs_to :department
# Columns changed to foreign keys in later migrations
t.string :comment_id # Initially string
change_column :table, :comment_id, :bigint # Changed later
Recognizes indexes in multiple formats:
# Single column indexes
add_index :users, :company_id
# Multi-column indexes
add_index :users, [:company_id, :department_id]
# Index defined in a separate migration
add_index :albums, :comment_id
- Uses
schema.rb
as the source of truth - Catches foreign keys created across multiple migrations
- Detects when string/text columns are changed to foreign keys
- Validates against existing indexes
- Add this file to
.github/workflows/check_migration_indexes.yml
- The action automatically runs on PRs with migration changes
- Enable debug mode by setting
DEBUG: "1"
in the workflow
The action provides detailed error messages:
Error: Missing index for foreign key column 'comment_id' in table 'albums'
Details:
- Column type: bigint (64-bit integer typically used for foreign keys)
- Column appears to be a foreign key (ends with _id)
- Please add an index to improve query performance
- You can add it using: add_index :albums, :comment_id
# Single migration with index
class AddCompanyToUsers < ActiveRecord::Migration[7.0]
def change
add_column :users, :company_id, :bigint
add_index :users, :company_id
end
end
# References with index
class CreateOrders < ActiveRecord::Migration[7.0]
def change
create_table :orders do |t|
t.references :user, index: true
t.timestamps
end
end
end
# Multi-column index
class AddDepartmentToUsers < ActiveRecord::Migration[7.0]
def change
add_column :users, :department_id, :bigint
add_index :users, [:company_id, :department_id]
end
end
# Missing index
class AddCompanyToUsers < ActiveRecord::Migration[7.0]
def change
add_column :users, :company_id, :bigint
# Missing index!
end
end
# Foreign key created across migrations
class CreateAlbums < ActiveRecord::Migration[7.0]
def change
create_table :albums do |t|
t.string :comment_id # Starts as string
end
end
end
class ChangeCommentIdType < ActiveRecord::Migration[7.0]
def change
change_column :albums, :comment_id, :bigint # Changed to foreign key
# Needs an index!
end
end
Enable detailed logging by setting the DEBUG environment variable:
- name: Check migrations for missing indexes
env:
DEBUG: "1"
run: ...
Debug output includes:
- Detected foreign key columns
- Found indexes
- Schema parsing details
- Column type information
-
Bigint Columns (
t.bigint
)- 64-bit integers typically used for foreign keys
- Standard in modern Rails applications
-
Integer Columns (
t.integer
)- 32-bit integers commonly used for foreign keys
- Legacy or smaller range foreign keys
-
References (
t.references
,t.belongs_to
)- Rails association helpers
- Automatically adds
_id
suffix
- Always add indexes when creating foreign key columns
- Use
t.references
withindex: true
for cleaner migrations - Consider composite indexes for frequently combined queries
- Add indexes in the same migration where foreign keys are created
- Don't forget indexes when changing column types to foreign keys
- Only detects columns ending in
_id
- Assumes standard Rails naming conventions
- Requires
schema.rb
(notstructure.sql
) - Cannot detect custom foreign key naming patterns
Feel free to open issues or PRs for:
- Additional foreign key patterns
- New index detection methods
- Better error messages
- Performance improvements
This project is available under the MIT License.