Как стать автором
Обновить

RESTful routing

Ruby
В прошлой статье про роуты я много о чем еще не написал, но Iskin заметил, что я ничего не написал про RESTful routing. Это очень важная часть маршрутинга на рельсах. Общей картины о REST у меня не было, были лишь вырванные оттуда отсюда общие представления. Так что я решил взяться за это поосновательнее.

Есть много литературы, но она наверняка не переведена. И есть пара скринкастов, которые я просмотрел:
Скринкаст №35 «Custom REST Actions» Райана Бейтса
Скринкаст №93 «RESTful Rails» Бала Паранжа — он более основательный и представляет собой часовую лекцию в университете. Еще у него индийский английский =).
Отличный перевод статей по поводу REST

' />

REST


REpresentational State Transfer of Resources
Простоты ради сформулирую так: это такая система организации ссылок. А ссылки — это запросы клиент-сервер. А запросы это в первую очередь HTTP метод!

REST — это больше, чем просто системы ссылок, но практическое применение в рельсах это именно создание запросов и работа с ресурсами

В былые времена мне и в голову не приходило указывать метод запроса в ссылке (в форме — дело другое, и то ограничивался GET и POST). Теперь в помощь нам мы имеем (конечно, они были и раньше) четыре HTTP метода: GET, POST, PUT, DELETE. Теперь главными являются не методы контроллера, но методы HTTP.

Еще одна новость: для нас больше нет URL'ов. Теперь мы используем URI — Uniform Resource Identifier — ссылка на ресурс. Путь RESTful — указание URI и HTTP метода.

К примеру, у нас есть ресурс — книги (books). Каждой книге соответствует его уникальный ID. Ссылка на удаление, просмотр и апдейт данных какого-нибудь экземпляра (c ID=1, скажем) будет выглядеть так:

mysite/books/1

Но как же программа поймет, какое из трех действий мы хотим выполнить? Вот здесь в помощь URI приходит HTTP method:

GET mysite/books/1 — покажи нам информацию о книге с ID = 1
POST mysite/books/1 — обновит информацию о книге
DELETE mysite/books/1 — удалит книгу

Рельсовая ссылка будет выглядеть (на удаление, скажем) так:

<%= link_to 'Delete book', book_url(ID), :method => :delete %>

Магия


Подобные роуты берутся не из воздуха, а прописываются в конфигурационном файле routes.rb.

#routes.rb
map.resources :books

Эта коротенькая строчка создаст для нас семь стандартных роутов:
# HTTP    path_var           path            action
  GET     books_path         /books          index
  GET     book_path(id)      /books/id       show
  GET     new_book_path      /books/new      new
  POST    books_path         /books          create
  GET     edit_book_path(id) /books/id/edit  edit
  PUT     book_path(id)      /books/id       update
  DELETE  book_path(id)      /books/id       destroy

Бала Паранж предлагает понимать RESTful роуты как предложения:
Покажи мне список книг: GET books_path = GET /books
Покажи мне форму редактирования для книги с ID=1: GET edit_book_path(1) = GET /books/1/edit
Удали книгу 1: DELETE book_path(1) = DELETE /books/1
Обнови данные для книги 1: PUT book_path(1) = PUT /books/1
etc

Как быть если мы хотим создать еще один метод. К примеру метод antique, который выдает нам список древних фолеантов из нашего каталога. В итоге мы хотим получить ссылку вида
# HTTP    path_var            path            action
  GET     antique_books_path  /books/antique  antique

Есть две опции для ресурсов: :member и :collection. В данном случае наш метод работает (возвращает) коллекцию — список книг (то есть много книг, хотя может не вернуть и ни одной), поэтому мы используем опцию :collection. Кроме того, так как antique _возвращает_ нам список, то мы должны использовать HTTP метод GET. Если это трудно понять, то можно действовать по аналогии: наш метод по сути делает то же самое, что и метод index — значит и HTTP методы у них должны быть одинаковыми.

#routes.rb
map.resources :books, :collection => { :antique => :get }


Теперь создадим еще два метода:
fire — сжечь все фолеанты
repeblish — переиздать книгу
Тогда роуты будут выглядеть так:

#routes.rb
map.resorces :books, :collection => { :antique => :get, :fire => :delete}, :member => { :republish => :put }


# HTTP    path_var            path            action
  GET     antique_books_path  /books/antique  antique
  DELETE  fire_books_path     /books          fire
  PUT     book_path(id)       /books/id       republish

Почему republish использует метод PUT? Потому что он обновляет данные (аналог update)
Почему fire_books_path использует метод DELETE? Потому что он удаляет (аналог destroy)

Разминка


А теперь давайте посмотрим на следующие ссылки и подумаем почему они не RESTful и как их сделать RESTful

1. GET /books/edit
2. DELETE /books/1/update
3. DELETE /books/1/destroy


1. Если мы что-то редактируем, то мы обязаны указать ID (не забываем, что все — ссылка на ресурс! URI!). Поэтому правильно было бы написать
GET /books/1/edit

2. Для обновления данных мы используем метод PUT, а не DELETE. Коме того указание HTTP метода достаточно, поэтому указание на метод update — лишнее
PUT /books/1

3. Опять же указание метода контроллера — лишнее
DELETE /books/1

А теперь давайте обсудим чего здесь не хватает =)
Теги:routesrubyrailsruby on railsrestful
Хабы: Ruby
Всего голосов 29: ↑25 и ↓4+21
Просмотры11K

Похожие публикации

Лучшие публикации за сутки