Creating a multi-tenant application using PostgreSQL's schemas and Rails

前端 未结 3 2059
攒了一身酷
攒了一身酷 2021-01-29 17:53

Stuff I\'ve already figured out

I\'m learning how to create a multi-tenant application in Rails that serves data from different schemas based on what domain or subdomai

相关标签:
3条回答
  • 2021-01-29 18:44

    Change line 38 to:

    conn.schema_search_path = "#{schema_name}, #{old_search_path}"
    

    I presume that postgres is trying to lookup existing table names when loading schema.rb and since you've set the search_path to only contain the new schema, it fails. This of course, is presuming you still have the public schema in your database.

    Hope that helps.

    0 讨论(0)
  • Update Dec 5, 2011

    Thanks to Brad Robertson and his team, there's the Apartment gem. It's very useful and does a lot of the heavy lifting.

    However, if you'll be tinkering with schemas, I strongly suggest knowing how it actually works. Familiarize yourself with Jerod Santo's walkthrough , so you'll know what the Apartment gem is more or less doing.

    Update Aug 20, 2011 11:23 GMT+8

    Someone created a blog post and walks though this whole process pretty well.

    Update May 11, 2010 11:26 GMT+8

    Since last night I've been able to get a method to work that creates a new schema and loads schema.rb into it. Not sure if what I'm doing is correct (seems to work fine, so far) but it's a step closer at least. If there's a better way please let me know.

    
      module SchemaUtils
       def self.add_schema_to_path(schema)
        conn = ActiveRecord::Base.connection
        conn.execute "SET search_path TO #{schema}, #{conn.schema_search_path}"
       end
    
       def self.reset_search_path
        conn = ActiveRecord::Base.connection
        conn.execute "SET search_path TO #{conn.schema_search_path}"
       end
    
       def self.create_and_migrate_schema(schema_name)
        conn = ActiveRecord::Base.connection
    
        schemas = conn.select_values("select * from pg_namespace where nspname != 'information_schema' AND nspname NOT LIKE 'pg%'")
    
        if schemas.include?(schema_name)
         tables = conn.tables
         Rails.logger.info "#{schema_name} exists already with these tables #{tables.inspect}"
        else
         Rails.logger.info "About to create #{schema_name}"
         conn.execute "create schema #{schema_name}"
        end
    
        # Save the old search path so we can set it back at the end of this method
        old_search_path = conn.schema_search_path
    
        # Tried to set the search path like in the methods above (from Guy Naor)
        # [METHOD 1]: conn.execute "SET search_path TO #{schema_name}"
        # But the connection itself seems to remember the old search path.
        # When Rails executes a schema it first asks if the table it will load in already exists and if :force => true. 
        # If both true, it will drop the table and then load it. 
        # The problem is that in the METHOD 1 way of setting things, ActiveRecord::Base.connection.schema_search_path still returns $user,public.
        # That means that when Rails tries to load the schema, and asks if the tables exist, it searches for these tables in the public schema.
        # See line 655 in Rails 2.3.5 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
        # That's why I kept running into this error of the table existing when it didn't (in the newly created schema).
        # If used this way [METHOD 2], it works. ActiveRecord::Base.connection.schema_search_path returns the string we pass it.
        conn.schema_search_path = schema_name
    
        # Directly from databases.rake. 
        # In Rails 2.3.5 databases.rake can be found in railties/lib/tasks/databases.rake
        file = "#{Rails.root}/db/schema.rb"
        if File.exists?(file)
         Rails.logger.info "About to load the schema #{file}"
         load(file)
        else
         abort %{#{file} doesn't exist yet. It's possible that you just ran a migration!}
        end
    
        Rails.logger.info "About to set search path back to #{old_search_path}."
        conn.schema_search_path = old_search_path
       end
      end
    
    0 讨论(0)
  • 2021-01-29 18:51

    Is there a gem/plugin that has these things already?

    pg_power provides this functionality to create/drop PostgreSQL schemas in migration, like this:

    def change
      # Create schema
      create_schema 'demography'
    
      # Create new table in specific schema
      create_table "countries", :schema => "demography" do |t|
        # columns goes here
      end
    
      # Drop schema
      drop_schema 'politics'
    end
    

    Also it takes care about correctly dumping schemas into schema.rb file.

    0 讨论(0)
提交回复
热议问题