2009-05-10 43 views
30

Làm cách nào để chuyển JSON vào ứng dụng RAILS để nó tạo các đối tượng con lồng nhau trong mối quan hệ has_many?Tạo đối tượng lồng nhau bằng JSON trong Rails

Đây là những gì tôi có cho đến thời điểm này:

Hai đối tượng mô hình.

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

class Location < ActiveRecord::Base 
    belongs_to :commute 
end 

Với đường đi làm, tôi có bộ điều khiển chuẩn được thiết lập. Tôi muốn có thể tạo một đối tượng Commute cũng như một vài đối tượng Location con trong một cuộc gọi REST bằng cách sử dụng JSON. Tôi đã cố gắng điều như thế này:

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 

Hoặc dễ đọc hơn, JSON là:

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

Khi tôi thực hiện điều đó, tôi nhận được kết quả này:

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' 

Có vẻ giống như các vị trí mảng JSON đang được đọc, nhưng không được hiểu là đối tượng Vị trí.

Tôi có thể dễ dàng thay đổi máy khách hoặc máy chủ, vì vậy giải pháp có thể đến từ cả hai phía.

Vì vậy, RAILS có giúp tôi dễ dàng thực hiện việc này không? Hoặc tôi có cần thêm một số hỗ trợ cho điều này vào đối tượng Đi làm của tôi không? Có lẽ thêm một phương thức from_json?

Cảm ơn bạn đã được trợ giúp.


Vì tôi đã làm việc thông qua việc này, một giải pháp hoạt động là sửa đổi bộ điều khiển của tôi. Nhưng điều này dường như không phải là cách "làm việc", vì vậy hãy cho tôi biết nếu có cách nào tốt hơn.

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 

Trả lời

35

Đã tìm ra, đối tượng địa điểm nên được gọi là locations_attributes để khớp với lược đồ đặt tên tạo đối tượng lồng nhau. Sau khi làm điều đó, nó hoạt động hoàn hảo với bộ điều khiển Rails mặc định.

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

Bạn dường như có khả năng kiểm soát nguồn JSON, nhưng nếu bạn không thể, bạn sẽ xử lý "vị trí" như thế nào? – Jerome

+0

Hãy xem, tôi vừa đăng một bản chỉnh sửa từ một câu trả lời đã bị xóa. –

+0

Đối với bất cứ ai vẫn gặp sự cố với điều này, bạn phải tự cho phép các thuộc tính trong bộ điều khiển của bạn. Ví dụ: 'params.require (: đường đi làm) .permit (: minutes,: startTime, locations_attributes: [: vĩ độ,: kinh độ])' – Kevin

0

Nếu bạn không thể dễ dàng thay đổi json bạn đang làm việc với, bạn chỉ có thể thực hiện new trên mô hình của bạn. Tôi đang sử dụng sau đây để wrangle json vào hình dạng dự kiến, trong trường hợp của tôi liên quan đến việc xóa khóa 'id' và một số không tồn tại trong mô hình địa phương của tôi. Tôi đã thực hiện điều này trong application_record.rb và các trường hợp đặc biệt trong mỗi mô hình.

def self.new(properties = {}) 
    super properties.select { |attr, _val| 
    (['id'] + attribute_types.keys).include?(attr.to_s) 
} 
Các vấn đề liên quan