一尘不染

在Rails中使用JSON创建嵌套对象

json

如何将JSON传递到RAILS应用程序,以便它将以has_many关系创建嵌套的子对象?

这是我到目前为止的内容:

两个模型对象。

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,但没有解释为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

阅读 243

收藏
2020-07-27

共1个答案

一尘不染

解决了这个问题,应该将locations对象称为locations_attributes,以与Rails嵌套对象创建命名方案匹配。之后,它可以与默认的Rails控制器完美配合。

{
    "commute": {
        "minutes": 0,
        "startTime": "Wed May 06 22:14:12 EDT 2009",
        "locations_attributes": [
            {
                "latitude": "40.4220061",
                "longitude": "40.4220061"
            }
        ]
    }
}
2020-07-27