From 656ed50d391ad68e8dc2a32f9072d1baa1126cfb Mon Sep 17 00:00:00 2001 From: James Le Cuirot Date: Fri, 25 Oct 2013 12:59:24 +0100 Subject: [PATCH 1/3] Don't assume default client search path Since ActiveRecord 3.2.14, db/structure.sql automatically includes a "SET search_path TO" statement before adding the "INSERT INTO schema_migrations" statements, which is handy. However, if you haven't set schema_search_path in your config/database.yml (I deliberately haven't) and you use multi_schema in your migrations then the search path will flip-flop between "$user",public and public depending on whether you've run "rake db:structure:dump" or "rake db:migrate". This makes version control tedious. The default client search path of "$user",public can be overridden in postgresql.conf so I have made this configurable through MultiSchema.default_search_path as part of this fix. --- lib/multi_schema/behaviors.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/multi_schema/behaviors.rb b/lib/multi_schema/behaviors.rb index dab6f5f..a8a103e 100644 --- a/lib/multi_schema/behaviors.rb +++ b/lib/multi_schema/behaviors.rb @@ -1,6 +1,7 @@ module MultiSchema module Behaviors @@disable_message = false + @@default_search_path = '"$user",public' def disable_message=(val) @@disable_message = val @@ -10,6 +11,14 @@ def disable_message @@disable_message end + def default_search_path=(val) + @@default_search_path = val + end + + def default_search_path + @@default_search_path + end + def with_in_schemas(options = nil) options = unify_type(options, Hash) { |items| {:only => items} } options[:only] = unify_type(options[:only], Array) { |item| item.nil? ? all_schemas : [item] }.map { |item| item.to_s } @@ -42,8 +51,8 @@ def current_schema end def reset_schema_path - puts "--- Restore Schema to public" unless disable_message - ActiveRecord::Base.connection.schema_search_path = 'public' + puts "--- Restore Schema to #{@@default_search_path}" unless disable_message + ActiveRecord::Base.connection.schema_search_path = @@default_search_path end def schema_path From 6bcf3a65be1db6ddf082536f865cee4b7820d98d Mon Sep 17 00:00:00 2001 From: Neil Duff-Howie Date: Wed, 16 Nov 2022 10:44:19 +0000 Subject: [PATCH 2/3] Fix for later postgres, clear AR cache on switch --- lib/multi_schema/behaviors.rb | 55 +++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/lib/multi_schema/behaviors.rb b/lib/multi_schema/behaviors.rb index a8a103e..06bf28a 100644 --- a/lib/multi_schema/behaviors.rb +++ b/lib/multi_schema/behaviors.rb @@ -38,7 +38,7 @@ def with_in_schemas(options = nil) def all_schemas ActiveRecord::Base.connection.select_values <<-END - SELECT * + SELECT nspname FROM pg_namespace WHERE nspname NOT IN ('information_schema') AND @@ -51,8 +51,10 @@ def current_schema end def reset_schema_path - puts "--- Restore Schema to #{@@default_search_path}" unless disable_message - ActiveRecord::Base.connection.schema_search_path = @@default_search_path + puts '--- Restore Schema to "$user", public' unless disable_message + ::ActiveRecord::Base.connection.schema_search_path = '"$user", public' + clear_cache + nil end def schema_path @@ -62,6 +64,12 @@ def schema_path def set_schema_path(schema) puts "--- Select Schema: #{schema} " unless disable_message ActiveRecord::Base.connection.schema_search_path = schema + clear_cache + nil + end + + def set_schema_and_public(schema) + set_schema_path "#{schema}, public" end def push_schema_to_path(schema) @@ -74,6 +82,34 @@ def pop_schema_from_path set_schema_path(new_path) end + def ensure_schema_reset + old = ::ActiveRecord::Base.connection.schema_search_path + + begin + yield + ensure + e = $ERROR_INFO + e = e.cause while e.respond_to?(:cause) + set_schema_path old unless e.is_a?(PG::Error) + end + end + + def with_schema_and_public(schema) + ensure_schema_reset do + set_schema_and_public schema + yield + end + end + + def each_schema_and_public + ensure_schema_reset do + (all_schemas - ['public']).each do |schema| + set_schema_and_public schema + yield schema + end + end + end + private def unify_type(input, type) @@ -89,5 +125,18 @@ def unify_array_item_type(input, type, &block) unify_type item, type, &block end end + + def clear_cache + ::ActiveRecord::Base.connection.schema_cache.clear! + + ::ActiveRecord::Base.descendants.map(&:base_class).uniq.each do |klass| + # reset_sequence_name would needlessly fetch them all now. + unless klass.instance_variable_get(:@explicit_sequence_name) + klass.instance_variable_set(:@sequence_name, nil) + end + end + + nil + end end end From c963b18f013f9c65b8f7763ba9f2d306dc3d98be Mon Sep 17 00:00:00 2001 From: Neil Duff-Howie Date: Wed, 16 Oct 2024 17:25:43 +0100 Subject: [PATCH 3/3] Add queriable 'service_schema' --- lib/multi_schema/behaviors.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/multi_schema/behaviors.rb b/lib/multi_schema/behaviors.rb index 06bf28a..95c5922 100644 --- a/lib/multi_schema/behaviors.rb +++ b/lib/multi_schema/behaviors.rb @@ -2,6 +2,7 @@ module MultiSchema module Behaviors @@disable_message = false @@default_search_path = '"$user",public' + @@service_schema = 'public' def disable_message=(val) @@disable_message = val @@ -19,6 +20,10 @@ def default_search_path @@default_search_path end + def service_schema + @@service_schema + end + def with_in_schemas(options = nil) options = unify_type(options, Hash) { |items| {:only => items} } options[:only] = unify_type(options[:only], Array) { |item| item.nil? ? all_schemas : [item] }.map { |item| item.to_s } @@ -53,6 +58,7 @@ def current_schema def reset_schema_path puts '--- Restore Schema to "$user", public' unless disable_message ::ActiveRecord::Base.connection.schema_search_path = '"$user", public' + @@service_schema = 'public' clear_cache nil end @@ -63,6 +69,7 @@ def schema_path def set_schema_path(schema) puts "--- Select Schema: #{schema} " unless disable_message + @@service_schema = schema.split(/\s*,\s*/).reject { |x| x == '"$user"' }.first ActiveRecord::Base.connection.schema_search_path = schema clear_cache nil