Диспетчер: с чего все начинается

Среда Rails используется для создания веб-приложений, поэтому сначала запрос обрабатывается веб-сервером: Apache, Lighttpd, Nginx и т. д. Затем сервер переправляет запрос приложению Rails, где он попадает к диспетчеру.

Обработка запроса

Выполнив свою часть обработки запроса, сервер передает диспетчеру различную информацию:

  • URI запроса (например, http://localhost:3000/timesheets/show/3 или что-то в этом роде);
  • окружение CGI (список имен параметров CGI и соответствующих им значений).

В задачу диспетчера входит:

  • выяснить, какой контроллер должен обработать запрос;
  • определить, какое действие следует выполнить;
  • загрузить файл нужного контроллера, который содержит определение
  • класса контроллера на языке Ruby (например, TimesheetsController);
  • создать экземпляр класса контроллера;
  • сказать этому экземпляру, какое действие нужно выполнить.

Все это происходит быстро и незаметно для вас. Маловероятно, что вам когда-нибудь придется копаться в исходном коде диспетчера; можете просто полагаться на то, что эта штука работает, и работает правильно. Но чтобы по-настоящему осмыслить путь Rails, важно понимать, что происходит внутри диспетчера. В частности, необходимо помнить, что различные части вашего приложения – это просто фрагменты (иногда весьма объемные) написанного на Ruby кода, которые загружаются в работающий интерпретатор Ruby.

Познакомимся с диспетчером поближе

В педагогических целях выполним функции диспетчера вручную. Так вы сможете лучше почувствовать поток управления в приложениях Rails.
Для этого небольшого упражнения запустим новое приложение Rails:

$ rails dispatch_me

Теперь создадим простой контроллер с действием index:

$ cd dispatch_me/
$ ruby ./script/generate controller demo index

Заглянув в код только что сгенерированного контроллера в файле app/controllers/demo_controller.rb, вы обнаружите в нем действие index:

class DemoController < ApplicationController
def index
end
end

Сценарий generate также автоматически создал файл app/views/demo/index.rhtml, который содержит шаблон представления, соответствующего этому действию. Шаблон включает некоторые подстановочные переменные. Чтобы не усложнять задачу, заменим его более простым файлом, который сможем опознать с первого взгляда. Сотрите все содержимое файла index.rhtml и введите такую строку:

Hello!

Ее не назовешь дизайнерским шедевром, но для наших целей сойдет. Итак, мы выстроили косточки домино в ряд, теперь пора толкнуть переднюю: диспетчер. Для этого запустим консоль Rails, находясь в каталоге приложения. Введите команду ruby script/console:

$ ruby script/console
Loading development environment.
>>

Теперь мы находимся в самом сердце приложения Rails, которое ожидает инструкций.

Обычно при передаче запроса диспетчеру Rails веб-сервер устанавливает две переменные окружения. Поскольку мы собираемся вызвать диспетчер вручную, эти переменные придется установить самостоятельно:

>> ENV['REQUEST_URI'] = "/demo/index"
=> "/demo/index"
>> ENV['REQUEST_METHOD'] = "get"
=> "get"

Теперь мы готовы обмануть диспетчер, заставив его думать, будто он получил запрос. На самом деле, диспетчер действительно получает запрос только не от сервера, а от человека, сидящего за консолью.
Вот как выглядит команда:

>> Dispatcher.dispatch

А вот и ответ от приложения Rails:

Content-Type: text/html; charset=utf-8
Set-Cookie: _dispatch_me_session_id=336c1302296ab4fa1b0d838d; path=/
Status: 200 OK
Cache-Control: no-cache
Content-Length: 7
Hello!

Мы вызвали метод dispatch класса Dispatcher, и в результате было выполнено действие index и рендеринг соответствующего шаблона (в том виде, в каком мы его оставили), к результатам рендеринга добавлены HTTP-заголовки, и все вместе возвращено нам.

Теперь представьте: если бы вы были не человеком, а веб-сервером, и проделали все то же самое, то сейчас могли бы вернуть документ, состоящий из заголовков и строки Hello!, клиенту. Именно так все и происходит. Загляните в подкаталог public приложения dispatch_me (или любого другого приложения Rails). Среди прочего вы найдете там следующие файлы диспетчера:

$ ls dispatch.*
dispatch.cgi dispatch.fcgi dispatch.rb

Каждый раз, когда Rails получает запрос, веб-сервер передает управление одному из этих файлов. Какому именно, зависит от конфигурации сервера. В конечном итоге, все они делают одно и то же: вызывают метод класса Dispatcher.dispatch, как мы перед этим сделали с консоли.

Вы можете пройти по следу и дальше, ознакомившись с файлом public/.htaccess и конфигурацией своего сервера. Но для понимания цепочки событий, возникающих при получении запроса к Rails, и той роли, которую играет в них контроллер, сказанного выше достаточно.

КОММЕНТАРИИ