lib/strong_migrations/migration.rb in strong_migrations-0.3.0 vs lib/strong_migrations/migration.rb in strong_migrations-0.3.1
- old
+ new
@@ -12,15 +12,12 @@
@direction = direction
super
end
def method_missing(method, *args, &block)
- table = args[0].to_s
-
unless @safe || ENV["SAFETY_ASSURED"] || is_a?(ActiveRecord::Schema) || @direction == :down || version_safe?
ar5 = ActiveRecord::VERSION::MAJOR >= 5
- model = table.classify
case method
when :remove_column, :remove_columns, :remove_timestamps, :remove_reference, :remove_belongs_to
columns =
case method
@@ -39,102 +36,90 @@
cols
end
code = ar5 ? "self.ignored_columns = #{columns.inspect}" : "def self.columns\n super.reject { |c| #{columns.inspect}.include?(c.name) }\n end"
- command = String.new("#{method} #{sym_str(table)}")
- case method
- when :remove_column, :remove_reference, :remove_belongs_to
- command << ", #{sym_str(args[1])}#{options_str(args[2] || {})}"
- when :remove_columns
- columns.each do |c|
- command << ", #{sym_str(c)}"
- end
- end
-
raise_error :remove_column,
- model: model,
+ model: args[0].to_s.classify,
code: code,
- command: command,
+ command: command_str(method, args),
column_suffix: columns.size > 1 ? "s" : ""
when :change_table
raise_error :change_table, header: "Possibly dangerous operation"
when :rename_table
raise_error :rename_table
when :rename_column
raise_error :rename_column
when :add_index
- columns = args[1]
- options = args[2] || {}
+ table, columns, options = args
+ options ||= {}
+
if columns.is_a?(Array) && columns.size > 3 && !options[:unique]
raise_error :add_index_columns, header: "Best practice"
end
- if postgresql? && options[:algorithm] != :concurrently && !@new_tables.to_a.include?(table)
- raise_error :add_index,
- table: sym_str(table),
- column: column_str(columns),
- options: options_str(options.except(:algorithm))
+ if postgresql? && options[:algorithm] != :concurrently && !@new_tables.to_a.include?(table.to_s)
+ raise_error :add_index, command: command_str("add_index", [table, columns, options.merge(algorithm: :concurrently)])
end
when :add_column
- column = args[1]
- type = args[2]
- options = args[3] || {}
+ table, column, type, options = args
+ options ||= {}
default = options[:default]
if !default.nil? && !(postgresql? && postgresql_version >= 110000)
raise_error :add_column_default,
- table: sym_str(table),
- column: sym_str(column),
- type: sym_str(type),
- options: options_str(options.except(:default)),
- default: default.inspect,
- code: backfill_code(model, column, default)
+ add_command: command_str("add_column", [table, column, type, options.except(:default)]),
+ change_command: command_str("change_column_default", [table, column, default]),
+ remove_command: command_str("remove_column", [table, column]),
+ code: backfill_code(table, column, default)
end
if type.to_s == "json" && postgresql?
if postgresql_version >= 90400
raise_error :add_column_json
else
raise_error :add_column_json_legacy,
- model: model,
- table: connection.quote_table_name(table)
+ model: table.to_s.classify,
+ table: connection.quote_table_name(table.to_s)
end
end
when :change_column
+ table, column, type = args
+
safe = false
# assume Postgres 9.1+ since previous versions are EOL
- if postgresql? && args[2].to_s == "text"
- column = connection.columns(table).find { |c| c.name.to_s == args[1].to_s }
- safe = column && column.type == :string
+ if postgresql? && type.to_s == "text"
+ found_column = connection.columns(table).find { |c| c.name.to_s == column.to_s }
+ safe = found_column && found_column.type == :string
end
raise_error :change_column unless safe
when :create_table
- options = args[1] || {}
+ table, options = args
+ options ||= {}
+
raise_error :create_table if options[:force]
- (@new_tables ||= []) << table
+
+ # keep track of new tables of add_index check
+ (@new_tables ||= []) << table.to_s
when :add_reference, :add_belongs_to
- options = args[2] || {}
+ table, reference, options = args
+ options ||= {}
+
index_value = options.fetch(:index, ar5)
if postgresql? && index_value
- reference = args[1]
- columns = []
- columns << "#{reference}_type" if options[:polymorphic]
- columns << "#{reference}_id"
+ columns = options[:polymorphic] ? [:"#{reference}_type", :"#{reference}_id"] : :"#{reference}_id"
+
raise_error :add_reference,
- command: method,
- table: sym_str(table),
- reference: sym_str(reference),
- column: column_str(columns),
- options: options_str(options.except(:index))
+ reference_command: command_str(method, [table, reference, options.merge(index: false)]),
+ index_command: command_str("add_index", [table, columns, {algorithm: :concurrently}])
end
when :execute
raise_error :execute, header: "Possibly dangerous operation"
when :change_column_null
- _, column, null, default = args
+ table, column, null, default = args
if !null && !default.nil?
raise_error :change_column_null,
- code: backfill_code(model, column, default)
+ code: backfill_code(table, column, default)
end
end
StrongMigrations.checks.each do |check|
instance_exec(method, args, &check)
@@ -142,11 +127,11 @@
end
result = super
if StrongMigrations.auto_analyze && @direction == :up && postgresql? && method == :add_index
- connection.execute "ANALYZE VERBOSE #{connection.quote_table_name(table)}"
+ connection.execute "ANALYZE VERBOSE #{connection.quote_table_name(args[0].to_s)}"
end
result
end
@@ -174,28 +159,27 @@
# escape % not followed by {
stop!(message.gsub(/%(?!{)/, "%%") % vars, header: header || "Dangerous operation detected")
end
- def sym_str(v)
- v.to_sym.inspect
- end
+ def command_str(command, args)
+ str_args = args[0..-2].map { |a| a.inspect }
- def column_str(columns)
- columns = Array(columns).map(&:to_sym)
- columns = columns.first if columns.size == 1
- columns.inspect
- end
-
- def options_str(options)
- str = String.new("")
- options.each do |k, v|
- str << ", #{k}: #{v.inspect}"
+ # prettier last arg
+ last_arg = args[-1]
+ if last_arg.is_a?(Hash)
+ if last_arg.any?
+ str_args << last_arg.map { |k, v| "#{k}: #{v.inspect}" }.join(", ")
+ end
+ else
+ str_args << last_arg.inspect
end
- str
+
+ "#{command} #{str_args.join(", ")}"
end
- def backfill_code(model, column, default)
+ def backfill_code(table, column, default)
+ model = table.to_s.classify
if ActiveRecord::VERSION::MAJOR >= 5
"#{model}.in_batches.update_all #{column}: #{default.inspect}"
else
"#{model}.find_in_batches do |records|\n #{model}.where(id: records.map(&:id)).update_all #{column}: #{default.inspect}\n end"
end