class RubbyCop::Cop::Rails::ReversibleMigration
This cop checks whether the change method of the migration file is reversible.
@example
# bad def change change_table :users do |t| t.column :name, :string end end # good def change create_table :users do |t| t.string :name end end # good def change reversible do |dir| change_table :users do |t| dir.up do t.column :name, :string end dir.down do t.remove :name end end end end
@example
# drop_table # bad def change drop_table :users end # good def change drop_table :users do |t| t.string :name end end
@example
# change_column_default # bad def change change_column_default(:suppliers, :qualification, 'new') end # good def change change_column_default(:posts, :state, from: nil, to: "draft") end
@example
# remove_column # bad def change remove_column(:suppliers, :qualification) end # good def change remove_column(:suppliers, :qualification, :string) end
@example
# remove_foreign_key # bad def change remove_foreign_key :accounts, column: :owner_id end # good def change remove_foreign_key :accounts, :branches end
@see api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html
Constants
- MSG
Public Instance Methods
on_send(node)
click to toggle source
# File lib/rubbycop/cop/rails/reversible_migration.rb, line 117 def on_send(node) return unless within_change_method?(node) return if within_reversible_block?(node) check_irreversible_schema_statement_node(node) check_drop_table_node(node) check_change_column_default_node(node) check_remove_column_node(node) check_remove_foreign_key_node(node) end
Private Instance Methods
all_hash_key?(args, *keys)
click to toggle source
# File lib/rubbycop/cop/rails/reversible_migration.rb, line 204 def all_hash_key?(args, *keys) return false unless args && args.hash_type? hash_keys = args.to_a.map do |arg| arg.to_a.first.children.first.to_sym end hash_keys & keys == keys end
check_change_column_default_node(node)
click to toggle source
# File lib/rubbycop/cop/rails/reversible_migration.rb, line 147 def check_change_column_default_node(node) change_column_default_call(node) do |args| unless all_hash_key?(args.first, :from, :to) add_offense( node, :expression, format(MSG, 'change_column_default(without :from and :to)') ) end end end
check_drop_table_node(node)
click to toggle source
# File lib/rubbycop/cop/rails/reversible_migration.rb, line 136 def check_drop_table_node(node) drop_table_call(node) do unless node.parent.block_type? add_offense( node, :expression, format(MSG, 'drop_table(without block)') ) end end end
check_irreversible_schema_statement_node(node)
click to toggle source
# File lib/rubbycop/cop/rails/reversible_migration.rb, line 130 def check_irreversible_schema_statement_node(node) irreversible_schema_statement_call(node) do |method_name| add_offense(node, :expression, format(MSG, method_name)) end end
check_remove_column_node(node)
click to toggle source
# File lib/rubbycop/cop/rails/reversible_migration.rb, line 158 def check_remove_column_node(node) remove_column_call(node) do |args| if args.to_a.size < 3 add_offense( node, :expression, format(MSG, 'remove_column(without type)') ) end end end
check_remove_foreign_key_node(node)
click to toggle source
# File lib/rubbycop/cop/rails/reversible_migration.rb, line 169 def check_remove_foreign_key_node(node) remove_foreign_key_call(node) do |arg| if arg.hash_type? add_offense( node, :expression, format(MSG, 'remove_foreign_key(without table)') ) end end end
within_change_method?(node)
click to toggle source
# File lib/rubbycop/cop/rails/reversible_migration.rb, line 180 def within_change_method?(node) parent = node.parent while parent if parent.def_type? method_name, = *parent return true if method_name == :change end parent = parent.parent end false end
within_reversible_block?(node)
click to toggle source
# File lib/rubbycop/cop/rails/reversible_migration.rb, line 192 def within_reversible_block?(node) parent = node.parent while parent if parent.block_type? _, block_name = *parent.to_a.first return true if block_name == :reversible end parent = parent.parent end false end