5

私の目的は、1 つの REST リクエストでネストされたリソースを作成することです。REST 要求は、XML ドキュメントを介して表されます。単一のリソースでは問題なく機能しますが、ネストされたリソースでは管理できませんでした。OK、次に少し例を挙げます。

最初に新しい Rails プロジェクトを作成します

rails forrest

次に、木と鳥の巣という 2 つのリソースの足場を生成します。

./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 で、以下に「belongs_to」行を挿入します。これは、すべての鳥の巣がツリーに属する必要があるためです。

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

OK、これまでのところすべて問題ありません。ゴムが道路と出会うポイントが来ます。1 つのリクエストで両方のリソースを作成します。1 つの鳥の巣を含むツリーの 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

...そして、ツリーのコントローラーの (生成された) "create" メソッドでサーバー エラーが発生します: AssociationTypeMismatch (BirdNest expected, got Array)

私の見解では、これは受信した属性とエラー メッセージに関するサーバーのログの重要な部分です。

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 構文はどれですか? または、このケースは生成されたものでカバーされていないため、ツリーのコントローラーを手動で変更する必要がありますか?

4

4 に答える 4

3

これを実現する 1 つの方法は、ツリー モデルで bird_nests= メソッドをオーバーライドすることです。

def bird_nests=(attrs_array)
  attrs_array.each do |attrs|
    bird_nests.build(attrs)
  end
end

ここでの唯一の問題は、セッターのデフォルトの動作が失われることです。これは、アプリの問題である場合とそうでない場合があります。

より新しいバージョンの Rails を実行している場合は、ここで説明されているように一括割り当てをオンにするだけです。

http://github.com/rails/rails/commit/e0750d6a5c7f621e4ca12205137c0b135cab444a

そしてここ:

http://ryandaigle.com/articles/2008/7/19/what-s-new-in-edge-rails-nested-models

class Tree < ActiveRecord::Base
  has_many :bird_nests, :accessible => true
end

これは推奨されるオプションです。

于 2009-02-17T13:58:57.817 に答える
2

この質問は 2 年半前に尋ねられましたが、今では多くのことが変更されています。最初は Rails 2.3 でメソッドを使用しhas_many :bird_nests, :accessible => true、現在は Rails 3 でaccepts_nested_attributes_forメソッドを使用しています...したがって、最近の Rails 3 では、次のコードで上記の目的を達成できます。

class Tree < ActiveRecord::Base
  has_many :bird_nests
  accepts_nested_attributes_for :bird_nests
end

class BirdNest < ActiveRecord::Base
   belongs_to :tree
end

これにより、Tree オブジェクトの bird_nests_attributes アクセサー (getter/setter) が生成されます。したがって、xml は次のようになります。

<tree>
  <name>Cherry</name>
  <bird_nests_attributes type='array'>
      <bird_nest>
          <bird-type>Blackbird</bird-type>
          <eggs-count>2</eggs-count>
      </bird_nest>
      <bird_nest>
          <bird-type>Bluebird</bird-type>
          <eggs-count>3</eggs-count>
      </bird_nest>
  </bird_nests_attributes>
</tree>

Rails は上記の XML を適切な params ハッシュに変換し、bird_nests オブジェクトが関連付けられた Tree オブジェクトが次のステートメントで作成されます。

@tree = Tree.new(params[:tree])
@tree.save

これは、動作させるための最小限のコードです。常に必要なモデルで使用している場合は、次のようにリストattr_accessibleに追加することを忘れないでください。:bird_nests_attributesattr_accessible

attr_accessible :a_tree_attribute, :another_tree_attr, :bird_nests_attributes

同様に、属性の検証をそれぞれのモデルに追加できます。また、検証が失敗した場合、ネストされた属性のエラーも@tree.errorsリストに表示されます。これが、Googleで同じ質問を検索した他の人に役立つことを願っており、この古い投稿がトップの結果になりました.

于 2011-08-21T01:30:08.100 に答える
2

ツリー モデルのbird_nests=メソッドのオーバーライドは、Patrick Richie の以前の投稿 (感謝) を参照して、有効な解決策です。したがって、コントローラーの変更は必要ありません。以下は、上記の例で説明した特定の XML リクエストを処理するコードの詳細です (配列以外のネストも処理します)。

  def bird_nests=(params)
    bird_nest=params[:bird_nest] 
    if !bird_nest.nil?
      if bird_nest.class==Array
        bird_nest.each do |attrs|
          bird_nests.build(attrs)
        end
      else 
        bird_nests.build(bird_nest)
      end
    end
  end
于 2009-02-17T22:42:09.510 に答える
1

デフォルトのコントローラーには次のような行があります

@tree = Tree.new(params[:tree])

これは、送信したパラメーターを自動的に解析しないようです。コントローラーを変更して、パラメーター hashf を分離し、ツリーを作成して保存し、ツリーの ID (保存するまで作成されません) を使用してネストを作成し、ツリーを保存します。

泥のように透明?

于 2009-02-17T13:33:24.650 に答える