Моя цель - создать вложенные ресурсы с помощью одного запроса REST. Запросы REST представлены в виде XML-документа. Это хорошо работает для отдельных ресурсов, но я не мог управлять этим для вложенных. Хорошо, я приведу небольшой пример в следующем.
Сначала создайте новый проект рельсов
rails forrest
Затем мы создаем леса из двух ресурсов: деревьев и птичьих гнезд.
./script/generate scaffold tree name:string
./script/generate scaffold bird_nest tree_id:integer bird_type:string eggs_count:integer
В файле ./forrest/app/models/tree.rb мы вставляем строку «has_many» ниже, потому что дерево может иметь много птичьих гнезд: -)
class Tree < ActiveRecord::Base
has_many :bird_nests
end
В файле ./forrest/app/models/bird_nest.rb мы вставляем строку «принадлежать» ниже, потому что гнездо каждой птицы должно принадлежать дереву.
class BirdNest < ActiveRecord::Base
belongs_to :tree
end
После этого мы настраиваем базу данных и запускаем сервер:
rake db:create
rake db:migrate
./script/server
Просто скопируйте и вставьте этот XML-фрагмент в файл с именем tree.xml ...
<tree>
<name>Apple</name>
</tree>
... и отправьте его в службу cURL для создания нового дерева:
curl -H 'Content-type: application/xml' -H 'Accept: application/xml' -d @tree.xml http://localhost:3000/trees/ -X POST
Это отлично работает. Также для XML птичьего гнезда (имя файла «bird-nest.xml») отдельно. Если мы отправим это ...
<bird-nest>
<tree-id>1</tree-id>
<bird-type>Sparrow</bird-type>
<eggs-count>2</eggs-count>
</bird-nest>
... также с помощью следующего оператора cURL. Этот ресурс создан правильно!
curl -H 'Content-type: application/xml' -H 'Accept: application/xml' -d @bird-nest.xml http://localhost:3000/bird_nests/ -X POST
ОК, пока все хорошо. Теперь наступает момент, когда резина встречается с дорогой. Мы создаем оба ресурса в одном запросе. Итак, вот XML для нашего дерева, которое содержит птичье гнездо:
<tree>
<name>Cherry</name>
<bird-nests>
<bird-nest>
<bird-type>Blackbird</bird-type>
<eggs-count>2</eggs-count>
</bird-nest>
</bird-nests>
</tree>
Мы запускаем соответствующий запрос, снова используя cURL ...
curl -H 'Content-type: application/xml' -H 'Accept: application/xml' -d @tree-and-bird_nest.xml http://localhost:3000/trees/ -X POST
... и теперь мы получим ошибку сервера в (сгенерированном) методе «создания» контроллера дерева: AssociationTypeMismatch (ожидается BirdNest, получен массив)
На мой взгляд, это важная часть журнала сервера относительно полученных атрибутов и сообщения об ошибке:
Processing TreesController#create (for 127.0.0.1 at 2009-02-17 11:29:20) [POST]
Session ID: 8373b8df7629332d4e251a18e844c7f9
Parameters: {"action"=>"create", "controller"=>"trees", "tree"=>{"name"=>"Cherry", "bird_nests"=>{"bird_nest"=>{"bird_type"=>"Blackbird", "eggs_count"=>"2"}}}}
SQL (0.000082) SET NAMES 'utf8'
SQL (0.000051) SET SQL_AUTO_IS_NULL=0
Tree Columns (0.000544) SHOW FIELDS FROM `trees`
ActiveRecord::AssociationTypeMismatch (BirdNest expected, got Array):
/vendor/rails/activerecord/lib/active_record/associations/association_proxy.rb:150:in `raise_on_type_mismatch'
/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb:146:in `replace'
/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb:146:in `each'
/vendor/rails/activerecord/lib/active_record/associations/association_collection.rb:146:in `replace'
/vendor/rails/activerecord/lib/active_record/associations.rb:1048:in `bird_nests='
/vendor/rails/activerecord/lib/active_record/base.rb:2117:in `send'
/vendor/rails/activerecord/lib/active_record/base.rb:2117:in `attributes='
/vendor/rails/activerecord/lib/active_record/base.rb:2116:in `each'
/vendor/rails/activerecord/lib/active_record/base.rb:2116:in `attributes='
/vendor/rails/activerecord/lib/active_record/base.rb:1926:in `initialize'
/app/controllers/trees_controller.rb:43:in `new'
/app/controllers/trees_controller.rb:43:in `create'
Так что мой вопрос в том, что я делаю неправильно в отношении вложенности ресурсов XML. Какой будет правильный синтаксис XML? Или мне нужно вручную модифицировать контроллер дерева, так как этот случай не охватывается сгенерированным?