Class: RuboCop::Cop::Discourse::NoAddReferenceOrAliasesActiveRecordMigration
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::Discourse::NoAddReferenceOrAliasesActiveRecordMigration
- Defined in:
- lib/rubocop/cop/discourse/no_add_reference_active_record_migrations.rb
Overview
The methods:
-
add_reference
-
add_belongs_to
-
t.references
-
t.belongs_to
in ActiveRecord migrations are magic, and they all do some unexpected things in the background. For example, by default add_reference adds an index at the same time, but not concurrently, which is a nightmare for large tables.
Instead, inside a disable_ddl_transaction! migration we should create the new column (with any defaults and options required) and the index concurrently using hand-written SQL. This also allows us to handle IF NOT EXISTS cases, which enable re-runnable migrations. Also we can pick a better name for the index at the same time.
# bad def up
add_reference :posts, :image_upload
# or add_belongs_to :posts, :image_upload
# or t.references :image_upload when doing create_table do |t|
# or t.belongs_to :image_upload when doing create_table do |t|
end
# good disable_ddl_transaction! def up
execute "ALTER TABLE posts\nADD COLUMN IF NOT EXISTS image_upload_id bigint\n"
execute "CREATE INDEX CONCURRENTLY IF NOT EXISTS\nindex_posts_on_image_upload_id ON posts USING btree (image_upload_id)\n"
end
Constant Summary collapse
- MSG =
"AR methods add_reference, add_belongs_to, t.references, and t.belongs_to are\nhigh-risk for large tables and have too many background magic operations.\nInstead, write a disable_ddl_transactions! migration and write custom SQL to\nadd the new column and CREATE INDEX CONCURRENTLY. Use the IF NOT EXISTS clause\nto make the migration re-runnable if it fails partway through.\n"
Instance Method Summary collapse
Instance Method Details
#on_send(node) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/rubocop/cop/discourse/no_add_reference_active_record_migrations.rb', line 72 def on_send(node) if [ using_add_reference?(node), using_add_belongs_to?(node), using_t_references?(node), using_t_belongs_to?(node), ].none? return end add_offense(node, message: MSG) end |