Маршрутизация в Rails

Введение

Маршрутизатор - это привратник вашего приложения. Необходимо знать, какой метод контроллера будет обрабатывать приходящий от браузера в ваше приложение запрос. Должно ли приложение вывести страницу для создания нового пользователя? Или необходимо отредактировать существующего в соответствии с полученными данными?

Маршрутизатор - это просто служба распознавания входящих запросов. Она анализирует HTTP методы (GET, POST, PUT, DELETE) и URL полученного извне запроса, и сопоставляет их с подходящим методом контроллера для передачи ему управления. Это достаточно простая служба, но при этом весьма важная. Если она не найдет маршрут, удовлетворяющий запросу, ваше приложение выдаст ошибку.

Вместе с запросом, Rails обрабатывает все приходящие с ним параметры и делает их доступными для вас в специальном хэше params, который вы сможете использовать потом в контроллере. Это часто используется для передачи данных из форм, которые создают или изменяют объекты.

Если вы откроете файл маршрутов в вашем приложении (config/routes.rb), вы увидите хорошо откомментированное содержимое, поясняющее принцип работы этого функционала. Вам будет сложно сбиться с пути при работе с маршрутами.

Маршрутизации посвящены куча учебников и курсов, и в ретроспективе они кажутся достаточно простыми, но я помню изучение Rails и затруднения с пониманием этого функционала. К счастью, команда $ rake routes выведет все маршруты, доступные в вашем приложении. В этом разделе мы разберем происходящее с этим файлом.

Пункты для размышления

Постарайтесь ответить на предложенные вопросы. После выполнения задания попробуйте ответить на них ещё раз

  • Что такое "корневой" маршрут?
  • Перечислите семь RESTful маршрутов для ресурса.
  • Какие RESTful маршруты имеют тот же самый URL, но с другими методами?
  • Как указать ID или другую переменную в маршруте?
  • Какой легкий способ создать семь RESTful маршрутов в Rails?
  • Какой хелпер в Rails создает HTML ссылку?

Корневой маршрут

Наиболее важный (и простейший) маршрут в файле - это корневой маршрут. Куда попадут пользователи, когда укажут в браузере http://supercutekittenphotos.com? Просто скажите Rails, какой контроллер и действие должны обработать этот маршрут, вот так:

    root to: "kittens#index"  #kittens controller, index action (method)

Помните, под "действием" мы подразумеваем "метод внутри контроллера, который так и называется". Например, действие index - это просто метод index, который определен в контроллере KittensController

RESTful маршруты

Как мы обсуждали ранее, в REST существует семь основных типов действий, которые вы можете (и должны) сделать "ресурсом", то есть объектом, как пост или пользователь... чем-то, что обладает моделью данных. Это следующие методы (цитата из того урока):

  1. Получите все посты, с помощью GET (используя "index")
  2. Получите один из постов, также с помощью GET (используя "show")
  3. Используйте GET для получения страницы создания нового поста (здесь будет нужен "new" )
  4. Используйте POST для отправки введенных вами данных формы на сервер, для создания нового поста (здесь нужен "create")
  5. Вызовите с помощью GET пост на редактирование (используя "edit")
  6. С помощью PUT (или PATCH) отправьте измененные данные в посте на сервер (используйте "update")
  7. Удалите какой-нибудь пост, отослав на сервер запрос DELETE ("delete" соответственно)

Выделенные слова относятся к стандартным методам контроллера Rails!

Каждый из них представляет "RESTful" маршрут, и вы должны отредактировать config/routes.rb, чтобы приходящие к приложению запросы направлялись к соответствующему действию контроллера (в данном случае к контроллеру "PostsController"). Вот длинная запись для этих маршрутов:

get "/posts" => "posts#index"
get "/posts/:id" => "posts#show"
get "/posts/new" => "posts#new"
post "/posts" => "posts#create"  # обычно отправляемая пользователем заполненная форма
get "/posts/:id/edit" => "posts#edit"
put "/posts/:id" => "posts#update" # обычно отправляемая пользователем заполненная форма
delete "/posts/:id" => "posts#destroy"

Каждый из этих маршрутов по сути метод Ruby, сопоставляющий URL и метод HTTP с соответствующим действием контроллера. Здесь необходимо отметить два момента:

  1. Как мы видим, некоторые маршруты ведут на ТОТ ЖЕ URL... и только различные методы HTTP позволяют Rails направить запрос к соответствующему действию контроллера. Этот нюанс запутывает множество новичков.
  2. Во-вторых, мы видим, что перед полем "id" стоит двоеточие. Это говорит Rails: "запиши эту часть запроса в хэш params". Таким образом, мы можем выполнить GET запрос к первому и пятому посту по тому же маршруту, просто указав другой ID:
/posts/1  # ведет к действию #show контроллера "Postscontroller"
/posts/5  # также ведет к действию #show контроллера "Postscontroller"

Вы можете использовать этот ID напрямую из контроллера, получив его из хэша params.

Путь Rails для создания Restful маршрутов

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

# файл config/routes.rb
  ...
  resources :posts
  ...

Вот и все. С помощью этого метода Ruby мы получаем все семь записей. Никакой магии.

Rake Routes и методы-помощники

Как будут выглядеть ваши маршруты с этой строчкой? Если вы выполните $ rake routes в командной строке, то получите все маршруты, известные вашему приложению, например:

    edit_post  GET  /posts/:id/edit(.:format)  posts#edit

В середине записи вы видите метод HTTP и URL, затем действие контроллера, на которые они ведут. Это вам уже знакомо по предыдущему материалу. Запись (.:format) означает, что нет требований к такому расширению, как например .doc в конце маршрута, а в случае его наличия оно будет записано в хэш params для последующего использования. Но что же находится слева? Это "имя" маршрута.

Во многих ситуациях вам будет необходимо создать URL для определенного маршрута, например для навигации по сайту (но никогда НЕ используйте для этого хардкодинг, иначе при изменении URL вам придется каждую из них менять вручную). Для этой цели Rails предоставляет удобный метод-помощник link_to, для которого вам необходимо указать текст ссылки и ее URL.

    link_to "Edit this post", edit_post_path(3) # не зашивайте в код цифру 3!

Забегая немного вперед, можно сказать, что вторым аргументом должен быть путь или URL, так что мы используем метод-помощник для их генерации. edit_post_path(3) создаст путь /posts/3/edit.

Rails автоматически генерирует эти методы, которые соотносятся с именами всех ваших маршрутов. Такие методы оканчиваются на _path и _url. _path, как в случае с edit_post_path(3), сформирует относительный путь, который будет достаточен для большинства случаев. _url же сформирует полный URL.

Любые маршруты, которым необходимо указать ID и другие параметры, потребуют от вас их добавления и в методы-помощники (аналогично, как это было сделано выше для edit_post_path).
В строку запроса можно также добавить дополнительный параметр:

    post_path(3, referral_link: "/some/path/or/something")

Теперь параметр referral_link будет доступен в хэше params вашего контроллера, в дополнение к обычному набору параметров.

Маршруты в действиях контроллера

Возвращаясь к тому, как маршруты соотносятся с действиями контроллера, рассмотрим простой пример контроллера на основе сгенерированных методом resources :posts маршрутов:

    # в app/controllers/posts
    class PostsController < ApplicationController

      def index
        # простой код, запрашивающий все посты для
        # отображения их в представлении Index (index.html.erb)
      end

      def show
        # простой код, запрашивающий только один пост для
        # отображения его в представлении Show (show.html.erb)
      end

      def new
        # простой код, создающий пустой пост и отсылающий пользователю
        # представление New (new.html.erb), которое содержит
        # форму для создания поста
      end

      def create
        # код, создающий новый пост на основании параметров, которые
        # были заполнены в форме (и теперь доступны в
        # хэше `params`)
      end

      def edit
        # простой код для поиска необходимого поста, отсылающий затем
        # пользователю представление Edit (edit.html.erb), содержащее
        # форму редактирования поста
      end

      def update
        # код, определяющий, какой пост необходимо обновить, затем
        # обновляющий атрибуты этого поста. После этого,
        # он перенаправляет на другую страницу, например Show для
        # этого поста
      end

      def destroy
        # простой код, находящий требуемы пост и удаляющий его,
        # а после этого перенаправляющий пользователя в любое подходящее место.
      end

    end

Я не хочу все семь маршрутов!

Иногда нет необходимости во всех RESTful маршрутах, которые предоставляет метод resources. В таком случае, вы либо указываете только необходимые маршруты, используя only, или указываете нежелательные, используя except:

    resources :posts, only: [:index, :show]
    resources :users, except: [:index]

Не-RESTful маршруты

Конечно, вы не обязаны все делать через RESTful. Иногда необходимо создать отдельный маршрут и направить его в нестандартное действие контроллера. Просто следуйте примерам, которые были даны в начале раздела RESTful маршрутов:

    get '/somepath' => 'somecontroller#someaction'

... и комментарии в config/routes.rb вам окажут большую помощь в составлении таких маршрутов.

Задание

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

  1. Прочтите разделы 1-2.5, 3.1-3.4 и 4.6 главы о маршрутизации в Rails.

Дополнительные ресурсы

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

  • Пройдите этот курс от CodeSchool - Уровень 1 бесплатен и посвящен маршрутам.

  • Также пройдите этот курс - Уровень 1 также бесплатен и рассказывает о REST, Маршрутах, Ограничениях и Пространствах имен.

Поделиться уроком: