Создание многопользовательского приложения с использованием схем PostgreSQL и Rails

вещи, которые я уже понял

Я изучаю, как создать многопользовательское приложение в Rails, которое обслуживает данные из разных схем на основе того, какой домен или поддомен используется для просмотра приложения.

у меня уже есть несколько вопросов ответил:

  1. как вы можете заставить subdomain-fu работать с доменами? вот кто-то, кто задал тот же вопрос что приводит вас к этот блог.
  2. какая база данных и как она будет структурирована? вот отличный разговор Гая Наора, а лучше вопрос о PostgreSQL и схемы.
  3. Я уже знаю, что мои схемы будут иметь одинаковую структуру. Они будут отличаться по данным, которые они хранят. Итак,как вы можете запускать миграции для всех схем? здесь ответ.

те 3 пункта покрывают много общие вещи, которые мне нужно знать. Однако на следующих шагах у меня, похоже, есть много способов реализации. Я надеюсь, что есть лучший, более простой способ.

наконец, на мой вопрос

когда новый пользователь регистрируется, я могу легко создать схему. Однако,каков был бы лучший и самый простой способ загрузить структуру, которую уже имеют остальные схемы? вот некоторые вопросы/сценарии, которые могут дать вам лучше идея.

  1. должен ли я передать его shell script это сбрасывает публичную схему во временную и импортирует ее обратно в мою основную базу данных (в значительной степени, как говорит Гай Наор в своем видео)? Вот краткое резюме / скрипт, который я получил от полезного #postgres на freenode. Хотя это, вероятно, сработает, мне придется делать много вещей за пределами рельсов, что делает меня немного неудобным.. что также приводит меня к следующему вопрос.
  2. есть ли способ сделать это прямо из Ruby on Rails? Например, создайте схему PostgreSQL, а затем просто загрузите схему базы данных Rails (schema.rb-я знаю, это запутанно) в эту схему PostgreSQL.
  3. есть ли gem / плагин, который уже имеет эти вещи? методы, такие как"create_pg_schema_and_load_rails_schema(the_new_schema_name)". Если нет, я, вероятно, буду работать над его созданием, но я сомневаюсь в том, насколько хорошо проверено это будет со всеми движущимися частями (особенно если я использую сценарий оболочки для создания и управления новыми схемами PostgreSQL).

спасибо, и я надеюсь, что не слишком долго!

3 ответов


Обновление 5 Декабря 2011

благодаря Брэду Робертсону и его команде, есть квартиры. Это очень полезно и делает много тяжелой работы.

однако, если вы будете возиться со схемами, я настоятельно рекомендую знать, как это на самом деле работает. Ознакомьтесь с прохождение игры Jerod Santo's, так что вы будете знать, что квартира драгоценный камень более или менее делает.

Обновление 20 Авг, 2011 11: 23 GMT+8

кто-то создал блоге и пусть гуляет весь этот процесс довольно хорошо.

обновление 11 мая 2010 11: 26 GMT+8

С прошлой ночи я смог получить метод для работы, который создает новую схему и загружает схему.РБ в этом. Не уверен, что то, что я делаю, правильно (пока работает нормально), но это, по крайней мере, шаг ближе. Если есть лучший способ, пожалуйста, дайте мне знать.


  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 пытается найти существующие имена таблиц при загрузке схемы.rb и поскольку вы установили search_path только для новой схемы,это не удается. Это, конечно, предполагает, что у вас все еще есть открытая схема в вашей базе данных.

надеюсь, что это поможет.


есть ли gem / плагин, который уже имеет эти вещи?

pg_power предоставляет эту функцию для создания / удаления схем 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

также он заботится о правильном сбрасывании схем в схему.файл rb.