Создание мультитенантного приложения с использованием схем PostgreSQL и Rails - PullRequest
45 голосов
/ 06 мая 2010

Материал, который я уже понял

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

Я уже ответил на несколько вопросов:

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

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

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

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

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

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

Ответы [ 3 ]

12 голосов
/ 29 октября 2010

Обновление от 5 декабря 2011 г.

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

Однако, если вы будете возиться со схемами, я настоятельно рекомендую знать, как это работает на самом деле. Ознакомьтесь с прохождением Джерода Санто , чтобы вы знали, что делает самоцвет «Квартира» более или менее.

Обновление 20 августа 2011 г. 11:23 GMT + 8

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

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

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


  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
3 голосов
/ 18 марта 2011

Измените строку 38 на:

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

Я предполагаю, что postgres пытается найти существующие имена таблиц при загрузке schema.rb, и, поскольку вы указали в search_path только новую схему, произойдет сбой. Это, конечно, предполагает, что у вас все еще есть общедоступная схема в вашей базе данных.

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

0 голосов
/ 14 августа 2013

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...