Skip to content

Instantly share code, notes, and snippets.

@GlenCrawford
Created April 17, 2020 13:59
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save GlenCrawford/16163abab7852c1bd550547f29971c18 to your computer and use it in GitHub Desktop.
Save GlenCrawford/16163abab7852c1bd550547f29971c18 to your computer and use it in GitHub Desktop.
Patching Rails database schema dumps to support multiple PostgreSQL schemas.
# Overrides Rails file activerecord/lib/active_record/schema_dumper.rb to
# include all schema information in the db/schema.rb file, for example, in the
# create_table statements. This allows for a working development database
# to be built from a schema.rb file generated by rake db:schema:dump.
#
# This is essentially a rebuild of the "schema_plus_multischema" gem (which is
# unfortunately only compatible with Rails ~> 4.2).
#
# Tested with Rails 6.0.
module ActiveRecord
class SchemaDumper
# Overridden in order to call new method "schemas".
def dump(stream)
header(stream)
extensions(stream)
schemas(stream)
tables(stream)
trailer(stream)
clean(stream)
stream
end
private
# Adds following lines just after the extensions:
# * connection.execute "CREATE SCHEMA ..."
# * connection.schema_search_path = ...
def schemas(stream)
@connection.schema_search_path.split(',').each do |name|
stream.puts %Q{ connection.execute "CREATE SCHEMA IF NOT EXISTS #{name}"}
end
stream.puts ""
stream.puts %Q{ connection.schema_search_path = #{@connection.schema_search_path.inspect}}
stream.puts ""
end
# Overridden in order to build a list of tables with their schema prefix
# (rest of the method is the same).
def tables(stream)
table_query = <<-SQL
SELECT schemaname, tablename
FROM pg_tables
WHERE schemaname = ANY(current_schemas(false))
SQL
sorted_tables = @connection.exec_query(table_query, 'SCHEMA').map do |table|
"#{table['schemaname']}.#{table['tablename']}"
end.sort
sorted_tables.each do |table_name|
table(table_name, stream) unless ignored?(table_name)
end
if @connection.supports_foreign_keys?
sorted_tables.each do |tbl|
foreign_keys(tbl, stream) unless ignored?(tbl)
end
end
end
end
end
@layerssss
Copy link

layerssss commented Nov 26, 2020

Hey the clean stream line seems to have been removed in 6.0.4.3

https://github.com/rails/rails/blob/v6.0.3.4/activerecord/lib/active_record/schema_dumper.rb#L41

To anyone getting error undefined method clean for ... just removed that line it will still work!

@lucascaton
Copy link

Hey Glen - this is great, thanks for sharing.
It'd be nice to get this merged into Rails! 🙂

@drnic
Copy link

drnic commented Feb 10, 2022

Thanks for this starting point.

We ended up with the following solution for our rails 7 app (if relevant) that builds off this gist https://gist.github.com/drnic/9d6e63802f1a7517434c25bb80f2ec09

@yesthesoup
Copy link

yesthesoup commented Nov 28, 2023

My thanks as well, and I was able to build off drnic's example for my own Rails 7 solution, including an initializer

https://gist.github.com/yesthesoup/7331b20c1ef025f38d6dea50dcd52395

@liaden
Copy link

liaden commented Feb 6, 2024

In looking options to handle this currently, I can see Rails 7.1 seems to have some logic for handling create_schema invocations: https://github.com/rails/rails/blob/7-1-stable/activerecord/lib/active_record/connection_adapters/postgresql/schema_dumper.rb#L31 unlike 7.0's branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment