使用PostgreSQL的模式和Rails创build一个多租户应用程序

我已经知道了

我正在学习如何在Rails中创build一个多租户应用程序,该应用程序根据用于查看应用程序的域或子域来提供来自不同架构的数据。

我已经有几个回答的问题了:

  1. 你怎么能得到子域福与域的工作呢? 这里有人问你把这个博客引向你的同一个问题 。
  2. 什么数据库,以及如何构build? Guy Naor的一个很好的演讲 ,以及有关PostgreSQL和模式的好问题 。
  3. 我已经知道我的模式都将具有相同的结构。 他们将持有的数据不同。 那么, 如何运行所有模式的迁移呢? 这是一个答案 。

这三点涵盖了我需要知道的很多常规内容。 然而,在接下来的步骤中,我似乎有很多方法来实现的东西。 我希望有一个更好,更简单的方法。

最后,对我的问题

当新用户注册时,我可以轻松创build架构。 然而, 加载其余模式已经具有的结构的最好和最简单的方法是什么? 这里有一些问题/情况可能会给你一个更好的主意。

  1. 我应该把它传递给一个shell脚本 ,将公共模式转换为临时脚本 ,并将其导回到我的主数据库(很像Guy Naor在他的video中所说的)? 以下是我从freenode上有用的#postgres获得的简短摘要/脚本 。 虽然这可能会起作用,但我必须在Rails之外做很多事情,这让我有点不舒服,这也让我接下来的问题。
  2. 有没有办法直接从Ruby on Rails做到这一点 ? 就像创build一个PostgreSQL模式一样,然后将Rails数据库模式(schema.rb – 我知道这很混乱)加载到PostgreSQL模式中。
  3. 有没有一个gem/插件已经有这些东西? 诸如“create_pg_schema_and_load_rails_schema(the_new_schema_name)”之类的方法。 如果没有的话,我可能会努力创build一个,但是我怀疑所有移动部分的testing效果如何(特别是如果我最终使用shell脚本来创build和pipe理新的PostgreSQL模式)。

谢谢,我希望不会太久!

更新2011年12月5日

感谢Brad Robertson和他的团队,这里有公寓gem 。 这是非常有用的,并做了很多繁重的工作。

但是,如果你要修改模式,我强烈build议知道它是如何工作的。 熟悉Jerod Santo的演练 ,你就会知道Apartment Gem或多或less在做什么。

更新8月20日,2011 11:23 GMT + 8

有人创build了一个博客文章,并走过这整个过程相当好。

更新2010年5月11日11:26 GMT + 8

自从昨天晚上,我已经能够获得一个方法来创build一个新的模式,并将schema.rb加载到其中。 不知道我在做什么是正确的(似乎到目前为止工作正常),但至less有一步。 如果有更好的方法,请让我知道。

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 

将第38行更改为:

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

我认为postgres在加载schema.rb时正在尝试查找现有的表名称,并且由于您已经将search_path设置为只包含新的模式,所以失败了。 这当然假定你的数据库中仍然有公共模式。

希望有所帮助。

有没有一个gem/插件已经有这些东西?

pg_power提供了这个function来在迁移中创build/删除PostgreSQL模式,如下所示:

 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 

而且它正确地将schema转储到schema.rb文件中。