Однажды понял, что я делаю под свои нужды достаточно много однотипных сайтов. Причем большинство доработок для каждого сайта носят исключительно косметический характер, непосредственно логика меняется редко и сразу для всех. Однако, меня очень сильно напрягает содержание большого количества копий одного и того же кода и его своевременное обновление. В итоге получается ситуация, что чем древнее проект, тем старее в нем версия кода и тем сложнее его поддерживать (с обратной совместимостью кода несколько сложновато). Плюс ко всему, везде разные административные интерфейсы, т.к. они эволюционируют быстрее всего.
В итоге у меня сформировались следующие пожелания к решению проблемы: 1. Программный комплекс, который может поддерживать неограниченное количество однотипных сайтов 2. Настраиваемый внешний вид для каждого сайта 3. Настраиваемый внешний вид для групп сайтов (скины) 4. Общий программный код 5. Единый хостинг и сервер (жадный я на выделение памяти под дополнительные монгрелы)
На ранних стадиях обдумывания этой идеи я наткнулся на фактически готовое решение: Productize your Rails App. Однако, по ряду причин оно мне не подошло. В частности, из-за того, что в тот момент я совершенно не представлял, как Rails выглядит изнутри и что он может. Это решение было сформировано в виде плагина (сейчас уж не найти его), однако с выходом Rails 1.0 плагин перестал работать, а автор забил болт и чинить не стал.
На дворе 2007 год, а плагина, реализующего нужный мне функционал, так и не видать. Идея, тем не менее, меня не оставляла и горела все сильнее. Опыта я уже достаточно набрался, понимания принципов Rails тоже, поэтому однажды сел и склеил таки небольшой плагин. Собственно, его и хочу продемонстрировать.
Скачивать отсюда
Установка
- Скопируйте плагин в папку vendor/plugins
Создайте модель Domains:
def self.up create_table :domains do |t| t.column :host, :string t.column :default, :boolean, :default => false t.column :theme, :string, :limit => 20 end end def self.down drop_table :domains endДобавьте хотя бы один домен в базу
Domain.create!(:host => "localhost", :default => true)
Это домен по умолчанию. В том случае, если запросу не соответствует ни один домен из базы, будет выбран этот домен.
- Создайте папки app/domains и app/themes, в них будут храниться файлы шаблонов для конкретных доменов и для скинов
Использование
При подключении плагин добавляет before_filter, который определяет текущий домен. Для этого домена используются соответствующие ему шаблоны из папки , а так же из папки .
Поиск осуществляется в следующем порядке: 1. в папке app/domains/#{current_domain.host} 2. если шаблон не найден, но задан скин для домена - в папке app/themes/#{current_domain.theme} 3. если ни в папке домена, ни в папке скина шаблон не найден - в стандартной папке app/views
Где может пригодится
Вы можете использвать этот плагин в проектах, которые требуют наличия нескольких доменов, подключенных к одному приложению. В частности, можно использвать это для организации поддоменов для различных разделов сайта, разделения аккаунтов по поддоменам или доменам (блоги, например), порталы.
Будьте внимательны
- Префикс www перед хостом убирается, домен с www и без обрабатывается одинаково (на мой взгляд, использование www - это скорее дань истории, нежели прямая необходимость)
- Плагин не делает различий между доменами второго, третьего и любого другого уровней. Хост нужно задавать целиком, исключая префикс www
- Постраничное кэширование через caches_page сохраняет сгенерированные страницы в папку public/#{current_domain.host} Пока я бы не рекоммендовал использовать плагин в проектах, применяющих постраничное кэширование. О применении плагина в этом ракурсе я расскажу чуть позже.
- Плагин пока что живет без тестов.
- Для тех кто в trunk'е: недавно был принят патч, который ходит где-то рядом с функционалом плагина. Я в ближайшие дни обновлюсь и адаптирую к последней версии Rails. На версии 1.2 работает корректно.