2009-05-10 24 views
30

JSONをRAILSアプリケーションに渡して、has_many関係でネストされた子オブジェクトを作成するにはどうすればよいですか?RailsでJSONを使用したネストされたオブジェクトの作成

これは私がこれまで持っているものです:

2つのモデルオブジェクト。

class Commute < ActiveRecord::Base 
    has_many :locations 
    accepts_nested_attributes_for :locations, :allow_destroy => true 
end 

class Location < ActiveRecord::Base 
    belongs_to :commute 
end 

標準のコントローラが設定されています。 JSONを使用して単一のREST呼び出しでCommuteオブジェクトと複数の子Locationオブジェクトを作成できるようにしたいと考えています。私はこのようなものをしようとしてきた:

curl -H "Content-Type:application/json" -H "Accept:application/json" 
-d "{\"commute\":{\"minutes\":0, 
\"startTime\":\"Wed May 06 22:14:12 EDT 2009\", 
\"locations\":[{\"latitude\":\"40.4220061\", 
\"longitude\":\"40.4220061\"}]}}" http://localhost:3000/commutes 

以上読み、JSONは次のとおりです。

{ 
    "commute": { 
     "minutes": 0, 
     "startTime": "Wed May 06 22:14:12 EDT 2009", 
     "locations": [ 
      { 
       "latitude": "40.4220061", 
       "longitude": "40.4220061" 
      } 
     ] 
    } 
} 

私は、私はこの出力を得ることを実行します。

Processing CommutesController#create (for 127.0.0.1 at 2009-05-10 09:48:04) [POST] 
    Parameters: {"commute"=>{"minutes"=>0, "locations"=>[{"latitude"=>"40.4220061", "longitude"=>"40.4220061"}], "startTime"=>"Wed May 06 22:14:12 EDT 2009"}} 

ActiveRecord::AssociationTypeMismatch (Location(#19300550) expected, got HashWithIndifferentAccess(#2654720)): 
    app/controllers/commutes_controller.rb:46:in `new' 
    app/controllers/commutes_controller.rb:46:in `create' 

それは見えますがJSON配列が読み込まれる場所のように、Locationオブジェクトとして解釈されません。

私は簡単にクライアントまたはサーバーのいずれかを変更できるので、どちらの側からも解決策が得られます。

これでRAILSはこれを簡単に行えますか?それとも、Commuteオブジェクトにこれをいくつかサポートする必要がありますか?おそらくfrom_jsonメソッドを追加しますか?

ありがとうございました。


私はこれを通じて取り組んできたように、作品一つの解決策は、私のコントローラを変更することです。しかし、これはそれを行う "レール"のように見えないので、もっと良い方法があれば私に知らせてください。

def create 
    locations = params[:commute].delete("locations"); 
    @commute = Commute.new(params[:commute]) 

    result = @commute.save 

    if locations 
     locations.each do |location| 
     @commute.locations.create(location) 
     end 
    end 


    respond_to do |format| 
     if result 
     flash[:notice] = 'Commute was successfully created.' 
     format.html { redirect_to(@commute) } 
     format.xml { render :xml => @commute, :status => :created, :location => @commute } 
     else 
     format.html { render :action => "new" } 
     format.xml { render :xml => @commute.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

答えて

35

実際には、ロケーションオブジェクトはlocations_attributesと呼ばれ、Railsのネストされたオブジェクト作成命名体系と一致していなければなりません。これを実行した後、デフォルトのRailsコントローラで完全に動作します。

{ 
    "commute": { 
     "minutes": 0, 
     "startTime": "Wed May 06 22:14:12 EDT 2009", 
     "locations_attributes": [ 
      { 
       "latitude": "40.4220061", 
       "longitude": "40.4220061" 
      } 
     ] 
    } 
} 
+1

ソースJSONを制御できるようですが、できない場合はどうすれば "場所"を扱うことができますか? – Jerome

+0

見て、私はちょうど削除された答えから編集を投稿しました。 –

+0

これに問題がある人は、コントローラの属性を手動で許可する必要があります。 例: ''場所**の代わりに** locations_attributes **を自動的に生成するにはどうすればいいですか? ': 'params.require(:通勤).permit(:分、:startTime、locations_attributes:[:緯度、経度])' – Kevin

0

あなたが簡単にあなたが作業しているJSONを変更できない場合、あなたは自分のモデルにnewを実装することができます。私は、私のケースでは、私の地元のモデルに存在しないいくつかの 'id'キーを削除する必要が予想される形状にjsonを論争するために、次の使用しています。私はこれをapplication_record.rbに実装し、各モデル内の特殊ケースを持っています。

def self.new(properties = {}) 
    super properties.select { |attr, _val| 
    (['id'] + attribute_types.keys).include?(attr.to_s) 
} 
関連する問題