Существует несколько вариантов работы с мультитенантным приложением.
Во-первых, вы можете добавить область к вашим таблицам (как предложено Чедом Бёрчем - используя company_id). Для большинства случаев использования это хорошо. Если вы обрабатываете данные, которые являются безопасными / конфиденциальными (например, учетная информация), вам нужно быть очень осторожным при тестировании, чтобы гарантировать, что данные остаются конфиденциальными.
Вы можете запустить свою систему, используя несколько баз данных. У вас может быть одно приложение, которое использует базу данных для каждого клиента, или у вас может быть отдельное приложение для каждого клиента. Запуск базы данных для каждого клиента немного режет зерно в рельсах, но это выполнимо. В зависимости от количества клиентов и ожидаемой нагрузки, я бы посоветовал взглянуть на запуск отдельных приложений. Немного поработав над настройками развертывания (capistrano, chef, puppet и т. Д.), Вы можете сделать этот процесс очень упрощенным. Каждый клиент работает в совершенно уникальной среде, и, если конкретный клиент имеет высокие нагрузки, вы можете раскрутить их на своем собственном сервере.
Если вы используете PostgreSQL, вы можете сделать что-то подобное, используя схемы.
Схемы PostgresQL предоставляют очень удобный способ изолировать ваши данные от разных клиентов. База данных содержит одну или несколько именованных схем, которые в свою очередь содержат таблицы. Вам нужно добавить несколько смартов в ваши миграции и развертывания, но это работает очень хорошо.
Внутри приложения Rails вы прикрепляете фильтры к запросу, которые включают или отключают схему текущего пользователя.
Что-то вроде:
before_filter :set_app
def set_app
current_app = App.find_by_subdomain(...)
schema = current_app.schema
set_schema_path(schema)
end
def set_schema_path(schema)
connection = ActiveRecord::Base.connection
connection.execute("SET search_path TO #{schema}, #{connection.schema_search_path}")
end
def reset_schema_path
connection = ActiveRecord::Base.connection
connection.execute("SET search_path TO #{connection.schema_search_path}")
end