2009-05-10 3 views
30

JSON을 RAILS 애플리케이션에 전달하여 has_many 관계로 중첩 된 자식 객체를 생성하는 방법은 무엇입니까?레일스에서 ​​JSON으로 중첩 된 객체 생성

다음은 내가 가지고있는 것입니다.

두 개의 모델 개체.

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 중첩 객체 생성 명명 스키마와 일치해야합니다. 그런 다음, 기본 레일즈 컨트롤러와 완벽하게 작동합니다. 당신은 쉽게 작업중인 JSON을 변경할 수없는 경우

{ 
    "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

여전히 문제가있는 사람은 컨트롤러의 속성을 수동으로 허용해야합니다. 예 : params.require (: commute) .permit (: 분, : startTime, locations_attributes : [: 위도, 경도])' – Kevin

0

, 당신은 당신의 모델 new을 구현할 수 있습니다. 나는 다음을 사용하여 json을 예상 된 모양으로 바꾸었다. 내 경우에는 'id'키와 내 로컬 모델에 존재하지 않는 일부 키를 삭제해야한다. 나는이 모델을 application_record.rb과 특수한 경우에 구현했다.

def self.new(properties = {}) 
    super properties.select { |attr, _val| 
    (['id'] + attribute_types.keys).include?(attr.to_s) 
} 
관련 문제