«Соглашения по конфигурации» — один из ключевых принципов, стоящих в основе Ruby on Rails. Он разрабатывался довольно специфическим образом, и, если вы будете следовать «пути Rails», всё будет работать вообще без настроек или с минимальными настройками. Вот почему Rails так популярна — если вы действуете согласно соглашений, то получите множество преимуществ, прикладывая меньше усилий, чем потребовалось бы при использовании иных объектных структур.
В этом отношении можно провести параллели с протоколом HTTP. Стоит только
отойти от основного пути, как окажется, что вы пытаетесь подобрать замену тем
основным вещам, которые совершенно свободно предоставляет сам HTTP.
Оставайтесь на пути и получите все преимущества, как, к примеру, кэширование
и прекрасную масштабируемость приложений меньшими усилиями. Хорошо
спроектированное — что обычно означает использование REST — веб-приложение
должно правильно использовать доступные методы HTTP, а не полагаться на
запросы
GET, чтобы изменять состояния сервера.
Идеал состоит в том, чтобы обратиться к другому оператору, основанному на
методе HTTP (на самом деле исполняющему иной код в зависимости от метода), и
сделать невозможным непреднамеренное изменение состояния с помощью запроса
GET.
Дело в том, что разработчики даже и не думают о HTTP просто потому, что до недавнего времени он не являлся объектом обсуждения подавляющего большинства разработчиков. И это обычное явление, что разработчик многого не знает о REST и HTTP, или не знает, почему они так важны. Но что, если эти соглашения были приняты в Rails, который постепенно подталкивает разработчиков на путь, облегчающий разработку приложений на REST?
Учитывая все это, я решил разработать плагин Rails для REST (RESTful Rails plugin), который бы облегчил создание REST-приложений в Rails. Проект был вдохновлен статьёй On HTTP Abuse, которая описывала возможности HTTP, не вполне поддерживаемые большинством объектных структур. Моя основная цель в том, чтобы обеспечить поддержку возможностям, которые ещё не включены в Rails, и, вместе с тем, минимально повлиять на путь разработки приложений в Rails.
В этой статье описывается очень простое приложение, использующее RESTful
Rails plugin. Чтобы следовать статье, понадобится установить последнюю версию
Rails (1.1.1. на момент написания статьи), а также любую базу данных. Я также
предполагаю наличие некоторых основных знаний о том, как сконфигурировать
выбранную базу данных для использования Rails, используя
config/database.yml. Также понадобится установить клиент
Subversion, поскольку он
потребуется для установки RESTful Rails plugin.
Для разрешения любых вопросов привожу ссылки на несколько прекрасных туториалов:
Если Rails уже установлен, можно произвести апгрейд до последней версии с помощью следующей команды:
gem install rails --include-dependencies
Потребуется как минимум версия Rails 1.1.1, чтобы следовать данной статье, поскольку некоторые из возможностей до недавнего времени не поддерживались.
Начну с описания примера, который будем использовать, простой проги, предназначенной для обработки личной книжной библиотеки. Чтобы создать проект Rails, введите следующее в командной строке:
rails --database=mysql library
Пожалуйста, обратите внимание, что опция
--database=mysql заставляет Rails переконфигурировать
config/database.yml для использования баз MySQL. Аналогично
можно воспользоваться любым из следующих параметров:
oracle
postgresql
sqlite2
sqlite3
Откроем директорию library, которая была только что создана для этого проекта:
cd library
Чтобы в данном примере нас ничто не отвлекало от REST, создадим модель
Book только с двумя атрибутами (
title и
description), а также не будем обрабатывать ошибки, как вы бы,
конечно же, сделали в настоящей проге.
Чтобы создать модель
Book, введём следующее в командной строке:
ruby script/generate model Book
Проверим новую модель, запустив тест её юнитов:
rake test:units
Вы увидите несколько ошибок, поскольку нам требуется сообщить Rails, как именно следует подключаться к базе данных.
Я использую MySQL, однако, вы можете использовать любую базу данных,
поддерживаемую Rails. Откройте
config/database.yml и измените его, чтобы можно было работать с
конфигурацией вашей базы данных.
В моём случае
config/database.yml выглядит следующим образом:
development:
adapter: mysql
database: library_development
username: root
password:
host: localhost
socket: /usr/local/mysql/run/mysql_socket
test:
adapter: mysql
database: library_test
username: root
password:
host: localhost
socket: /usr/local/mysql/run/mysql_socket
production:
adapter: mysql
database: library_production
username: root
password:
host: localhost
socket: /usr/local/mysql/run/mysql_socket
Обратите внимание, что я запускаю этот пример на тестовом сервере базы
данных на локальной машине. В системе производства вы не захотите
использовать учетную запись администратора. Единственное требование Rails
состоит в том, что пользователь должен иметь возможность использовать команды
CREATE и
DROP для работы с таблицами и указателями в дополнение к
стандартным командам SQL:
SELECT,
INSERT,
UPDATE и
DELETE.
Также убедитесь, что вы создали базы, перечисленные в
config/database.yml, используя способ, подходящий для вашей базы
данных. В моём случае я ввёл следующие команды для создания баз:
mysqladmin -u root create library_development
mysqladmin -u root create library_test
mysqladmin -u root create library_production
Команда
rake test:units все ещё должна выдавать ошибку, поскольку мы не
создали таблицу для книг.
Нам потребуется добавить таблицу для книг в разрабатываемую базу данных. Для этого воспользуемся системой перемещения Rails, которая позволяет определить способ, независящий от типа базы данных. Как только система перемещения будет запущена, она определит текущую версию схемы базы и обновит её до самой последней версии.
Начиная с версии Rails 1.1, всякий раз, как вы создаёте новую модель,
скрипт перемещения будет создан для неё автоматически. В нашем случае
скриптом перемещения для
Book является
db/migrate/001_create_books.rb. Обновите этот файл, чтобы он
стал выглядеть следующим образом:
class CreateBooks < ActiveRecord::Migration
def self.up
create_table :books do |t|
t.column :title, :string, :limit => 30, :null => false
t.column :description, :text
end
end
def self.down
drop_table :books
end
end
Это добавит в таблицу
books две колонки:
title и
description.
Теперь запустим перемещение:
rake db:migrate
Это обновит базу
development в
config/database.yml и добавит таблицу
books.
Теперь команда
rake test:units будет выполнена без ошибок!
Далее в данной статье мы будем пребывать либо в состоянии “all-tests passing state”; («все тесты проходят») , либо “failing state” («есть ошибки»). Мы будем перемещаться между этими двумя состояниями, как только приложение начнёт приобретать более отчётливые очертания.
До того, как мы погрузимся в работу с контроллером, нам потребуется тестовая информация, чтобы было с чем работать. Воспользуемся вспомогательной системой, чтобы загружать записи в тестовую базу данных каждый раз, когда будет запускаться тест юнита или функциональный тест.
Первым делом нам следует создать тест юнита, чтобы убедиться, что
вспомогательная система содержит нужную информацию. Замените метод
test_truth, содержащийся в
test/unit/book_test.rb по умолчанию, на следующее:
def test_fixture
assert_kind_of Book, books(:http_book)
assert_valid books(:http_book)
assert_equal 1, Book.count
end
Метод проверит, что в вспомогательной системе присутствует корректная
запись
:http_book и при том в единственном экземпляре. Если по какой-то
причине запись
:http_book не будет обнаружена, или таких записей будет больше
одной, тест юнита выдаст ошибку.
Команда
rake test:units выдаст ошибку, поскольку мы ещё не
сконфигурировали вспомогательную систему.
Rails автоматически создает наполнение для
test/fixtures/books.yml вспомогательной системы при создании
модели
Book. Обновите этот файл, чтобы он стал выглядеть следующим
образом:
http_book:
id: 1
title: "HTTP: The Definitive Guide"
description: "Everything that technical people need for using HTTP efficiently."
Теперь команда
rake test:units должна выполниться без ошибок.
Теперь мы можем быть совершенно уверены, что модель
Book и её наполнение могут быть использованы в дальнейшей
работе, так что перейдём к контроллеру, однако, сперва нам потребуется
установить RESTful Rails plugin.
RESTful Rails plugin
добавляет к стандартным контроллерам Rails несколько возможностей, которые
позволяют более эффективно использовать HTTP. В основе нашего примера самое
очевидное достоинство плагина: метод координации через HTTP. С ним у вас
появится возможность исполнять различный код в зависимости от метода запроса
HTTP. Неплохое дополнительное преимущество состоит в том, что метод также
берёт на себя обработку метода
OPTIONS, который нам понадобится в тестах.
Чтобы установить плагин, введите следующее в командную строку:
svn co svn://rubyforge.org/var/svn/restful-rails/trunk
vendor/plugins/restful-rails
Или же, если ваш проект использует контроль версий с помощью Subversion, установите его, используя систему плагина Rails:
ruby script/plugin install -x svn://rubyforge.org/var/svn/restful-rails/trunk
Обе эти команды могут создавать снимок последнего состояния RESTful Rails plugin и помещать его в директорию vendor/plugins/restful-rails/.
Теперь, поскольку плагин установлен, создадим контроллер.
Чтобы создать контроллер
BookController введите следующую команду:
ruby script/generate controller Book
Протестируем контроллер, запустив тесты функциональности:
rake test:functionals
Это должно пройти без ошибок.
Контроллер
BookController должен обрабатывать запросы на два URI:
| /books/ | Собрание книг |
| /books/{id} | Книга, идентифицируемая по ID |
Проверим, правильно ли обрабатываются URI.
Замените стандартный метод
test_truth в
test/functional/book_controller_test.rb следующим кодом:
def test_routing
with_options :controller => 'book' do |test|
test.assert_routing 'books', :action => 'collection'
test.assert_routing 'books/1', :action => 'by_id', :id => '1'
end
end
Это проверит, что URI ведут к правильному контроллеру и действию. Обратите
внимание на использование нового метода
with_options, который уменьшит ввод, позволив вам определить
опции по умолчанию для всех методов блока.
Команда
rake test:functionals должна выдать ошибку, поскольку мы ещё не
настроили, как URI должны вести к контроллерам.
Чтобы настроить маршрутизацию, нам требуется добавить в блок
ActionController::Routing::Routes.draw внутри
config/routes.rb следующую строчку:
map.connect_resource :book
Метод
connect_resource берётся из RESTful Rails plugin и настраивает
маршруты, которые подходят к требуемой структуре URI.
Команда
rake test:functionals теперь должна выполниться без ошибок.
Теперь, когда маршрутизация настроена, перейдём к контроллеру.
В данный момент контроллер даже не подозревает о RESTful Rails plugin.
Чтобы добавить координацию методов и другие возможности, необходимо вставить
RestController::Base в самое начало
app/controllers/book_controller.rb следующим образом:
class BookController < ApplicationController
include RestController::Base
end
Теперь всё готово, чтобы добавить ресурс
:collection в контроллер.
collection
Ресурс
:collection представляет собой список книг. Нам нужна
возможность просматривать список с помощью метода
GET и пополнять список, используя
POST. Добавим в
test/functional/book_controller_test.rb тест, чтобы убедиться,
что эти методы поддерживаются:
def test_options_collection
options :collection
assert_response HTTP::Status::NO_CONTENT
assert_no_entity
assert_allowed_methods :get, :post
end
С помощью этого происходит проверка, что при выполнении запроса
OPTIONS для
:collection, возвращается код состояния
204 No Content. Кроме того, заголовок
Allow должен индентифицировать методы
GET и
POST как разрешённые. Методы
options,
assert_no_entity и
assert_allowed_methods берутся из RESTful Rails plugin.
Команда
rake test:functionals должна выдать ошибку, поскольку в
контроллере ещё нет ресурса
:collection.
Первым делом, отключим ресурс
:collection, чтобы функциональные тесты пока что перестали
выдавать ошибки. А также следующее в
app/controllers/book_controller.rb:
resource :collection do |r|
r.post do
end
end
Теперь команда
rake test:functionals не выдаст ошибок.
Мы отключили пока только
POST, однако, ничего не было сказано о
GET. Ресурс RESTful Rails обрабатывает
GET практически так же, как и обычный метод Rails: если вы не
используете
redirect и
render, будет отображаться шаблон с тем же именем (если
доступен).
Пришел момент, когда нам потребуется тестовая информация, чтобы было с чем
работать. Мы ещё раз воспользуемся вспомогательной системой
Books, созданной нами для тестирования модели. Просто добавьте
следующую строчку в метод
setup в
test/functional/book_controller_test.rb:
fixtures :books
Пусть даже запросы
GET обрабатываются автоматически, нам все ещё необходимо
посмотреть, что произойдёт, когда выполнится
GET для
:collection. Нам требуется, чтобы шаблон собрания книг
загружался и отображался в виде списка всех книг базы данных в формате XML.
Чтобы убедиться в этом, добавим в
test/functional/book_controller_test.rb тест:
def test_get_collection
get :collection
assert_response HTTP::Status::OK
assert_template 'collection'
assert_equal 'application/xml', @response.content_type
with_options :tag => 'books' do |test|
test.assert_tag :children => { :count => 1, :only => { :tag => 'title', :content => 'Books' } }
test.assert_tag :children => { :count => 1, :only => { :tag => 'book', :content => '' } }
end
with_options :tag => 'book' do |test|
test.assert_tag :children => { :count => 1, :only => { :tag => 'id', :content => books(:http_book).id.to_s } }
test.assert_tag :children => { :count => 1, :only => { :tag => 'title', :content => books(:http_book).title } }
test.assert_tag :children => { :count => 1, :only => { :tag => 'link', :attributes => { :href => @controller.url_for(:action => 'by_id', :id => books(:http_book)) } } }
end
end
Это нужно, чтобы убедиться в том, что по выполнении
GET
:collection будет возвращён код состояния
200 OK. Также шаблон
collection должен использоваться для отображения результатов в
определённом формате XML.
Команда
rake test:functionals выдаст ошибку, поскольку мы ещё не создали
шаблон XML.
До того, как создать шаблон, нам потребуется способ получить список всех
книг из базы данных. Добавьте одну строчку в начало ресурса
:collection в
app/controllers/book_controller.rb:
resource :collection do |r|
conditions << @books = Book.find(:all)
r.post do
end
end
Обратите внимание, что присваивание
@book к
conditions согласуется с REST на Rails. Это разрешит обработку
условного запроса, который может быть в дальнейшем описан более детально.
Далее создайте шаблон
app/views/book/collection.rxml следующего вида:
xml.instruct!
xml.books do
xml.title 'Books'
@books.each do |book|
xml.book do
xml.id book.id
xml.title book.title
xml.link :href => url_for(:only_path => false, :action => 'by_id', :id => book)
end
end
end
Команда
rake test:functionals теперь не выдаст ошибок.
Итак, каким же образом нам следует обрабатывать
POST в
:collection? Ну, процесс состоит в том, чтобы добавить книгу в
базу, а также перенаправить клиента по адресу новой книги. Учитывая это,
добавим следующее в
test/functional/book_controller_test.rb:
def test_post_collection
new_book = { :title => 'test' }
post :collection, :book => new_book
assert_response HTTP::Status::CREATED
id = Book.maximum('id')
assert_location :action => 'by_id', :id => id
book = Book.find(id)
assert_kind_of Book, book
assert_equal new_book[:title], book.title
assert_equal new_book[:description], book.description
end
Это проверка на то, чтобы при выполнении
POST для
:collection, возвращался код состояния
201 Created. Кроме того, следует правильно установить заголовок
Location, а также выполнена проверка базы данных, что новая
книга была действительно внесена в базу.
Команда
rake test:functionals выдаст ошибку, поскольку мы не добавили
обработчик
POST для
:collection.
Для обработки запросов
POST перепишем обработчик
r.post в
app/controllers/book_controller.rb:
r.post do
@book = Book.new params[:book]
if @book.save
render_post_success :action => 'by_id', :id => @book
end
end
В этом примере мы используем
render_post_success метод из REST на Rails, который возвращает
код
201 Created и помещает URI новой книги в заголовок
Location.
Теперь команда
rake test:functionals выполнится без ошибок.
Теперь мы закончили с ресурсом
:collection. Он обрабатывает запросы
GET,
HEAD,
OPTIONS и
POST с помощью всего девяти строчек кода. Далее мы перейдём к
ресурсу
:by_id, который представляет собой книгу, используя её ID в базе
данных.
by_id
Ресурс
:by_id представляет собой одну из книг, идентифицируемую по её
ID в базе данных. Нам потребуется просматривать книгу с помощью метода
GET, вносить изменения с помощью
PUT, и удалять с помощью метода
DELETE. Добавим в
test/functional/book_controller_test.rb тест, который проверит
возможность перечисленного:
def test_options_by_id
options :by_id, :id => books(:http_book).id
assert_response HTTP::Status::NO_CONTENT
assert_no_entity
assert_allowed_methods :get, :put, :delete
end
С помощью этого мы сможем убедиться, что по выполнении
OPTIONS для
:by_id, будет возвращён код состояния
204 No Content. А также заголовок
Allow должен определять, что разрешены методы
GET,
PUT и
DELETE.
Команда
rake test:functionals должна выдать ошибку, поскольку для
ресурса
:by_id он ещё не создан.
Воспользуемся способом, очень похожим на тот, что мы применяли для ресурса
:collection — мы извлечем ресурс
:by_id, чтобы на данный момент тесты на функциональность
выполнялись без ошибок. Добавим следующие строки в
app/controllers/book_controller.rb:
resource :by_id do |r|
r.put do
end
r.delete do
end
end
И вновь, поскольку RESTful Rails plugin обрабатывает запросы так же, как и
обычный Rails, нам не требуется ничего предпринимать для обработки
GET.
Теперь команда
rake test:functionals выполнится без ошибок.
Нам следует проверить, что произойдёт, когда выполнится
GET для
:by_id. В нашем случае нам потребуется, чтобы шаблон
by_id загружался и отображал единственную книгу из базы данных в
формате XML. Убедимся в этом, добавив следующее в
test/functional/book_controller_test.rb:
def test_get_by_id
get :by_id, :id => books(:http_book).id
assert_response HTTP::Status::OK
assert_template 'by_id'
assert_equal 'application/xml', @response.content_type
with_options :tag => 'book' do |test|
test.assert_tag :children => { :count => 1, :only => { :tag => 'id', :content => books(:http_book).id.to_s } }
test.assert_tag :children => { :count => 1, :only => { :tag => 'title', :content => books(:http_book).title } }
test.assert_tag :children => { :count => 1, :only => { :tag => 'description', :content => books(:http_book).description } }
end
end
Это проверка на то, чтобы по выполнении GET для
:by_id возвращался код состояния
200 OK, а также шаблон
by_id использовался для отображения результатов в определённом
формате XML.
Команда
rake test:functionals должна выдать ошибку, поскольку мы ещё не
создали шаблон XML.
До создания шаблона нам в первую очередь потребуется найти способ извлечь
книгу из базы данных, используя ID из URI. Добавьте одну строчку в начало
ресурса
:by_id в
app/controllers/book_controller.rb, чтобы он стал выглядеть
так:
resource :by_id do |r|
conditions << @book = Book.find(params[:id])
r.put do
end
r.delete do
end
end
Далее создайте шаблон
app/views/book/by_id.rxml следующего вида:
xml.instruct!
@book.to_xml
Тест
rake test:functionals пройдёт без ошибок.
Теперь нам нужна возможность использовать
PUT для изменения книги по её ID. Мы протестируем эту
возможность, добавив следующее в
test/functional/book_controller_test.rb:
def test_put_by_id
changed_book = { :title => 'a different title', :description => 'a different description' }
id = books(:http_book).id
put :by_id, :id => id, :book => changed_book
assert_response HTTP::Status::NO_CONTENT
assert_no_entity
book = Book.find id
assert_kind_of Book, book
assert_equal changed_book[:title], book.title
assert_equal changed_book[:description], book.description
end
С помощью этого происходит проверка, что по выполнении
PUT для
:by_id будет возвращён код состояния
204 No Content. Тест проверит базу данных, чтобы убедиться, что
запись успешно была изменена.
Команда
rake test:functionals должна вернуть ошибку, поскольку мы ещё не
добавили обработчик
PUT для
:by_id.
Для обработки запросов
PUT обновим обработчик
r.put в
app/controllers/book_controller.rb с помощью следующих
строк:
r.put do
@book.attributes = params[:book]
if @book.save
render_put_success
end
end
Воспользуемся методом
render_put_success из RESTful Rails, который возвращает код
состояния
204 No Content.
Теперь команда
rake test:functionals должна выполниться без ошибок.
И, наконец, нам потребуется
DELETE для удаления книги по её ID.
Тест, который мы добавим в
test/functional/book_controller_test.rb выглядит следующим
образом:
def test_delete_by_id
id = books(:http_book).id
delete :by_id, :id => id
assert_response HTTP::Status::NO_CONTENT
assert_no_entity
assert_raise(ActiveRecord::RecordNotFound) { Book.find id }
end
С помощью этого теста мы удостоверимся, что по выполнении
DELETE для
:by_id будет возвращён код состояния
204 No Content. Тест делает проверку базу данных, чтобы
удостовериться, что запись была успешно удалена.
Команда
rake test:functionals должна выдать ошибку, поскольку мы ещё не
добавили обработчик
DELETE в
:by_id.
Для обработки запросов
DELETE приведём обработчик
r.delete в
app/controllers/book_controller.rb к следующему виду:
r.delete do
if @book.destroy
render_delete_success :id => nil
end
end
Это всего лишь вызовет
@book.destroy и в случае успеха выполнит
render_delete_success.
Теперь команда
rake test:functionals не выдаст ошибки.
Всегда приятно видеть, как успешно работает программа в тестовых случаях,
но что насчёт реального положения дел? Когда я пишу свои тесты, то люблю
делать двойную проверку, чтобы убедиться, что всё идеально работает. Давайте
напрямую выполним пару запросов, используя старый добрый
curl.
Прежде чем приступить, нам следует поднять тестовый сервер с помощью следующей команды:
ruby script/server
Теперь откроем второй экземпляр командной строки и выполним следующее:
curl http://localhost:3000/books/
Ожидаемый отклик выглядит так:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<title>Books</title>
</books>
Как можно видеть, в списке пока что нет ни одной книги.
Далее создадим одну книгу:
curl \
-i \
-X POST \
-H 'Content-Type: application/xml' \
-d '<book><title>a title</title><description>a description</description></book>' \
http://localhost:3000/books/
Ответ на данный запрос будет включать несколько заголовков, но нам нужны только некоторые:
HTTP/1.1 201 Created
Location: http://localhost:3000/books/1
Обратите внимание на URI в заголовке
Location, которым мы вот-вот воспользуемся.
Убедимся, что новая книга наличествует в собрании:
curl http://localhost:3000/books/
Ожидаемый ответ выглядит так:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<title>Books</title>
<book>
<id>1</id>
<title>a title</title>
<link href="http://localhost:3000/books/1"/>
</book>
</books>
Убедитесь, что ссылка в
href соответствует указанной в заголовке
Location, полученном нами на предыдущем шаге.
Последуем заголовку
Location из предыдущего шага:
curl http://localhost:3000/books/1
Ожидаемый ответ выглядит так:
<?xml version="1.0" encoding="UTF-8"?>
<book>
<title>a title</title>
<id type="integer">1</id>
<description>a description</description>
</book>
Обновите книгу, используя
PUT:
curl \
-i \
-X PUT \
-H 'Content-Type: application/xml' \
-d '<book><title>a new title</title><description>a new description</description></book>' \
http://localhost:3000/books/1
Это также возвратит несколько заголовков, но на данном этапе нам потребуется лишь первая строчка:
HTTP/1.1 204 No Content
Вновь возьмём книгу, чтобы просмотреть изменения:
curl http://localhost:3000/books/1
Ожидаемый ответ выглядит так:
<?xml version="1.0" encoding="UTF-8"?>
<book>
<title>a new title</title>
<id type="integer">1</id>
<description>a new description</description>
</book>
Мы удалим книгу следующим способом:
curl -i -X DELETE http://localhost:3000/books/1
И вновь мы получим несколько заголовков, но тот, из которого мы узнаем об
успешном выполнении
DELETE, расположен в первой строчке:
HTTP/1.1 204 No Content
Чтобы убедиться, что книга удалена, выполним запрос
GET:
curl http://localhost:3000/books/
Ожидаемый ответ выглядит так:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<title>Books</title>
</books>
Теперь собрание не содержит книг, как и ожидалось.
Итак, теперь у нас есть простое приложение на RESTful Rails, которое было
полностью протестировано, а также координация методов HTTP. Мы пользовались
HTTP-методом
OPTIONS, чтобы определить методы, поддерживаемые всеми
ресурсами, и мы основывали наши тесты на относительно простом протоколе из
REST.
Поскольку мы строили приложения на RESTful Rails с использованием Ruby on
Rails, то мы находимся лишь в начале пути к огромным возможностям. В данное
время интерес к HTTP и архитектуре REST постоянно растёт со стороны команды
разработчиков ядра Rails, а,
в частности, со
стороны Дэвида Хейнемейера Хэнссона. Проект RESTful Rails хорошо подготовлен
к старту за счёт координации методов; а на будующее запланированы: условный
GET, HTTP-идентификация и многое другое.
Учитывая мощное развитие Ruby on Rails, можно без оглядки утверждать, что в ближайшие месяцы вы увидие больше приложений на REST, а сообщество улучшит свое понимание протокола HTTP.