Rails & Postgres 架构转储冲突:如何避免重复创建Schema?
解决Rails多数据库Schema文件重复生成create_schema语句的问题
你的推测完全没错:Rails生成schema文件时会扫描整个数据库的所有架构和表,而不仅仅是当前连接指定的schema_search_path。所以哪怕db_one只配置了public架构,它的schema文件也会检测到数据库里存在custom_schema,自动加上create_schema "custom_schema"语句,最终导致加载数据库时提示架构已存在。
下面是几种靠谱的解决办法:
1. Rails 7+:用schema_dump配置指定导出的架构
直接在database.yml里给db_one加schema_dump.only配置,明确只导出public架构的内容:
test: db_one: database: test_db migrations_paths: db/migrate schema_search_path: public schema_dump: only: ["public"] # 只导出public架构相关语句 db_two: database: test_db migrations_paths: db/db_two_migrate schema_search_path: custom_schema,public
这样生成的db_one_schema.rb里就不会出现create_schema "custom_schema"了。
2. Rails 6及更早版本:自定义Schema导出逻辑
新建初始化文件config/initializers/schema_dumper.rb,重写SchemaDumper的逻辑,让它只导出当前连接schema_search_path里指定的架构:
ActiveRecord::SchemaDumper.prepend(Module.new do def tables(stream) # 只处理当前连接schema_search_path包含的架构下的表 filtered_tables = @connection.tables.select do |table| schema, _ = table.split('.') current_schemas = ActiveRecord::Base.connection.schema_search_path.split(',').map(&:strip) current_schemas.include?(schema || 'public') end filtered_tables.each { |table| table(stream, table) } end def schemas(stream) # 只导出当前连接schema_search_path包含的架构(跳过系统自带的架构) current_schemas = ActiveRecord::Base.connection.schema_search_path.split(',').map(&:strip) @connection.schemas.each do |schema| next if %w[information_schema pg_catalog].include?(schema) stream.puts " create_schema #{schema.inspect}" if current_schemas.include?(schema) end end end)
这个钩子会在导出schema时,只处理当前连接配置的架构内容,不会把其他架构的语句写到不相关的schema文件里。
3. 额外建议:把架构创建迁移归到指定数据库
确保custom_schema的创建迁移放在db_two的迁移目录(db/db_two_migrate)下,这样只有运行rails db:migrate:db_two时才会执行这个迁移。搭配上面的配置,就能彻底避免schema文件的冲突问题。
内容的提问来源于stack exchange,提问作者User
相关产品推荐
相关产品推荐

