Class: RuboCop::Cop::Migration::ChangeTableReferences

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/migration/change_table_references.rb

Overview

Prevent using ‘t.references` or `t.belongs_to` in a change_table. Internally, `t.references` use multiple `ALTER TABLE` statements. Since Rails cannot transform automatically `t.references` inside a `change_table bulk: true` we can manually create the equivalent `ALTER TABLE` statement using `t.bigint`, `t.index` and `t.foreign_key`.

#bad
change_table :subscriptions, bulk: true do |t|
  t.references :user, null: false, foreign_key: true
end

#good
change_table :subscriptions, bulk: true do |t|
  t.bigint :user_id, null: false
  t.index :user_id
  t.foreign_key :users, column: :user_id
end

Constant Summary collapse

MSG =
'Use a combination of `t.bigint`, `t.index` and `t.foreign_key` in a change_table to add a reference.' \
'Or `t.remove_foreign_key`, `t.remove` to remove a reference.'

Instance Method Summary collapse

Instance Method Details

#add_references_in_block?(node) ⇒ Object



28
29
30
# File 'lib/rubocop/cop/migration/change_table_references.rb', line 28

def_node_matcher :add_references_in_block?, <<~PATTERN
  (send lvar /references|belongs_to|remove_references|remove_belongs_to/ ...)
PATTERN

#change_table?(node) ⇒ Object



33
34
35
# File 'lib/rubocop/cop/migration/change_table_references.rb', line 33

def_node_matcher :change_table?, <<~PATTERN
  (block (send nil? :change_table ...) ...)
PATTERN

#on_block(node) ⇒ Object



37
38
39
40
41
42
43
44
45
46
# File 'lib/rubocop/cop/migration/change_table_references.rb', line 37

def on_block(node)
  return unless change_table?(node)

  references_node = node.child_nodes[2].each_node.detect { |n| add_references_in_block?(n) }
  return unless references_node

  arguments = references_node.child_nodes[1]
  references_methods_range = references_node.source_range.with(end_pos: arguments.source_range.begin_pos - 1)
  add_offense(references_methods_range)
end