lib/active_record/mti/schema_dumper.rb
require 'core_ext/hash'
# Modified SchemaDumper that knows how to dump
# inherited tables. Key is that we have to dump parent
# tables before we dump child tables (of course).
# In addition we have to make sure we don't dump columns
# that are inherited.
module ActiveRecord
# = Active Record Schema Dumper
#
# This class is used to dump the database schema for some connection to some
# output format (i.e., ActiveRecord::Schema).
module MTI
module SchemaDumper #:nodoc:
def dumped_tables
@dumped_tables ||= []
end
# Output table and columns - but don't output columns that are inherited from
# a parent table.
def table(table, stream)
return if already_dumped?(table)
new_stream = StringIO.new
super(table, new_stream)
string = new_stream.string
if (parent_table = @connection.parent_table(table))
table(parent_table, stream)
string = inject_inherits_for_create_table(string, table, parent_table)
string = remove_parent_table_columns(string, @connection.columns(parent_table))
pindexes = Hash[@connection.indexes(parent_table).map { |index| [index.columns, index] }]
cindexes = Hash[@connection.indexes(table).map { |index| [index.columns, index] }]
string = remove_parent_table_indexes(string, (pindexes & cindexes).values)
end
# We've done this table
dumped_tables << table
stream.write string
stream
end
def inject_inherits_for_create_table(string, table, parent_table)
tbl_start = "create_table #{remove_prefix_and_suffix(table).inspect}"
tbl_end = ' do |t|'
tbl_inherit = ", inherits: '#{parent_table}'"
string.gsub!(/#{Regexp.escape(tbl_start)}.*#{Regexp.escape(tbl_end)}/, tbl_start + tbl_inherit + tbl_end)
end
def remove_parent_table_columns(string, columns)
columns.each do |col|
string.gsub!(/\s+t\.\w+\s+("|')#{col.name}("|').*/, '')
end
string
end
def remove_parent_table_indexes(string, indexes)
indexes.each do |index|
string.gsub!(/\s*add_index .*name: #{Regexp.escape(index.name.inspect)}.*/, '') # Rails 4.x
string.gsub!(/\s+t\.index.*("|')#{index.name}("|').*/, '') # Rails 5.x
end
string
end
def remove_prefix_and_suffix(table)
table.gsub(/^(#{ActiveRecord::Base.table_name_prefix})(.+)(#{ActiveRecord::Base.table_name_suffix})$/, '\\2')
end
def already_dumped?(table)
dumped_tables.include? table
end
end
end
end