В прошлой статье про роуты я много о чем еще не написал, но Iskin заметил, что я ничего не написал про RESTful routing. Это очень важная часть маршрутинга на рельсах. Общей картины о REST у меня не было, были лишь вырванные оттуда отсюда общие представления. Так что я решил взяться за это поосновательнее.
Есть много литературы, но она наверняка не переведена. И есть пара скринкастов, которые я просмотрел:
Скринкаст №35 «Custom REST Actions» Райана Бейтса
Скринкаст №93 «RESTful Rails» Бала Паранжа — он более основательный и представляет собой часовую лекцию в университете. Еще у него индийский английский =).
Отличный перевод статей по поводу 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, скажем) будет выглядеть так:
Но как же программа поймет, какое из трех действий мы хотим выполнить? Вот здесь в помощь URI приходит HTTP method:
GET mysite/books/1 — покажи нам информацию о книге с ID = 1
POST mysite/books/1 — обновит информацию о книге
DELETE mysite/books/1 — удалит книгу
Рельсовая ссылка будет выглядеть (на удаление, скажем) так:
Подобные роуты берутся не из воздуха, а прописываются в конфигурационном файле routes.rb.
#routes.rb
Эта коротенькая строчка создаст для нас семь стандартных роутов:
Бала Паранж предлагает понимать 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, который выдает нам список древних фолеантов из нашего каталога. В итоге мы хотим получить ссылку вида
Есть две опции для ресурсов: :member и :collection. В данном случае наш метод работает (возвращает) коллекцию — список книг (то есть много книг, хотя может не вернуть и ни одной), поэтому мы используем опцию :collection. Кроме того, так как antique _возвращает_ нам список, то мы должны использовать HTTP метод GET. Если это трудно понять, то можно действовать по аналогии: наш метод по сути делает то же самое, что и метод index — значит и HTTP методы у них должны быть одинаковыми.
Теперь создадим еще два метода:
fire — сжечь все фолеанты
repeblish — переиздать книгу
Тогда роуты будут выглядеть так:
Почему republish использует метод PUT? Потому что он обновляет данные (аналог update)
Почему fire_books_path использует метод DELETE? Потому что он удаляет (аналог destroy)
А теперь давайте посмотрим на следующие ссылки и подумаем почему они не RESTful и как их сделать RESTful
1. Если мы что-то редактируем, то мы обязаны указать ID (не забываем, что все — ссылка на ресурс! URI!). Поэтому правильно было бы написать
GET /books/1/edit
2. Для обновления данных мы используем метод PUT, а не DELETE. Коме того указание HTTP метода достаточно, поэтому указание на метод update — лишнее
PUT /books/1
3. Опять же указание метода контроллера — лишнее
DELETE /books/1
А теперь давайте обсудим чего здесь не хватает =)
Есть много литературы, но она наверняка не переведена. И есть пара скринкастов, которые я просмотрел:
Скринкаст №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
А теперь давайте обсудим чего здесь не хватает =)