JSON 到 ActiveRecord(反序列化)
JSON to ActiveRecord (deserialize)
我正在使用 Ruby、Grape 和 ActiveRecord 构建网络 API。来自 ASP.NET Web API 我习惯于将模型从 JSON 自动绑定到 class 对象,然后可以使用 Entity Framework 保存该对象。我一直在搜索一下,看看在使用 ActiveRecord 时是否有类似的东西,但没有发现任何让我觉得我遗漏了一些非常明显的东西。将 JSON 反序列化为 ActiveRecord 模型的最佳方法是什么?
更新
Matts 回答对简单类型非常有效,但是当我有关联时,我收到以下错误:ActiveRecord::AssociationTypeMismatch:预期连接器(#70297711668780),得到哈希(#70297701477140)
这是我的代码 运行
class Card < ActiveRecord::Base
has_many :connectors, autosave: true
end
class Connector < ActiveRecord::Base
has_one :card
has_one :connected_card, :class_name => "Card", :foreign_key => "connected_card_id"
end
json = "{\"id\":\"1\", \"connectors\": [{\"id\": 1, \"card_id\":1}]}"
card = Card.new(ActiveSupport::JSON.decode(json))
您可以使用来自 ActiveSupport
的标准 JSON 解码,这将为您提供一个哈希值。
然后您需要从该散列构建一个新的 ActiveRecord
对象。
my_object = Foo.new(ActiveSupport::JSON.decode(some_json))
如果您希望它保存在一行中,请将 new
换成 create
。
在您的模型中 Card
您已经创建了一个名为连接器的关联。这是一个 ActiveRecord::Relation
方法,它需要来自 class Connector
的一堆模型。否则,您正在传递一个哈希数组。
{"id"=>"1", "connectors"=>[{"id"=>1, "card_id"=>1}]}
在你的 #new
方法中,它变成了这样的东西:
Card.new(id: 1, connectors: [{id: 1, card_id: 1}])
到达那里后,连接器数组应填充连接器实例,而不是散列。这就是失败的原因。
你有两个选择。首先是重命名控制器中 before_action 中的键并使用嵌套属性:
class Card < ActiveRecord::Base
has_many :connectors
accepts_nested_attributes_for :connectors
end
class CardsController < ApplicationController
before_action :set_nested
private
def set_nested
params["connectors_attributes"] = params.delete("connectors")
end
end
另一种选择是在模型中创建回调以从哈希创建对象。
class Card < ActiveRecord::Base
def initialize(params={})
params["connectors"] = params["connectors"].map {|connector| Connector.new(connector)}
super(params)
end
end
以上任何一项都将满足您的需求。 IMO 最好的是第一个,因为你不会重新定义 ActiveRecord#Methods
我正在使用 Ruby、Grape 和 ActiveRecord 构建网络 API。来自 ASP.NET Web API 我习惯于将模型从 JSON 自动绑定到 class 对象,然后可以使用 Entity Framework 保存该对象。我一直在搜索一下,看看在使用 ActiveRecord 时是否有类似的东西,但没有发现任何让我觉得我遗漏了一些非常明显的东西。将 JSON 反序列化为 ActiveRecord 模型的最佳方法是什么?
更新
Matts 回答对简单类型非常有效,但是当我有关联时,我收到以下错误:ActiveRecord::AssociationTypeMismatch:预期连接器(#70297711668780),得到哈希(#70297701477140)
这是我的代码 运行
class Card < ActiveRecord::Base
has_many :connectors, autosave: true
end
class Connector < ActiveRecord::Base
has_one :card
has_one :connected_card, :class_name => "Card", :foreign_key => "connected_card_id"
end
json = "{\"id\":\"1\", \"connectors\": [{\"id\": 1, \"card_id\":1}]}"
card = Card.new(ActiveSupport::JSON.decode(json))
您可以使用来自 ActiveSupport
的标准 JSON 解码,这将为您提供一个哈希值。
然后您需要从该散列构建一个新的 ActiveRecord
对象。
my_object = Foo.new(ActiveSupport::JSON.decode(some_json))
如果您希望它保存在一行中,请将 new
换成 create
。
在您的模型中 Card
您已经创建了一个名为连接器的关联。这是一个 ActiveRecord::Relation
方法,它需要来自 class Connector
的一堆模型。否则,您正在传递一个哈希数组。
{"id"=>"1", "connectors"=>[{"id"=>1, "card_id"=>1}]}
在你的 #new
方法中,它变成了这样的东西:
Card.new(id: 1, connectors: [{id: 1, card_id: 1}])
到达那里后,连接器数组应填充连接器实例,而不是散列。这就是失败的原因。
你有两个选择。首先是重命名控制器中 before_action 中的键并使用嵌套属性:
class Card < ActiveRecord::Base
has_many :connectors
accepts_nested_attributes_for :connectors
end
class CardsController < ApplicationController
before_action :set_nested
private
def set_nested
params["connectors_attributes"] = params.delete("connectors")
end
end
另一种选择是在模型中创建回调以从哈希创建对象。
class Card < ActiveRecord::Base
def initialize(params={})
params["connectors"] = params["connectors"].map {|connector| Connector.new(connector)}
super(params)
end
end
以上任何一项都将满足您的需求。 IMO 最好的是第一个,因为你不会重新定义 ActiveRecord#Methods