【问题标题】:JSON to ActiveRecord (deserialize)JSON 到 ActiveRecord(反序列化)
【发布时间】:2015-07-10 05:26:42
【问题描述】:

我正在使用 Ruby、Grape 和 ActiveRecord 构建一个 Web API。来自 ASP.NET Web API 我习惯于将模型从 JSON 自动绑定到类对象,然后可以使用 Entity Framework 保存该对象。在使用 ActiveRecord 时,我一直在寻找是否有与此类似的东西,但没有找到任何让我认为我错过了一些非常明显的东西的东西。将 JSON 反序列化为 ActiveRecord 模型的最佳方法是什么?

更新

Matts 答案非常适合简单类型,但是当我有关联时,我收到以下错误:ActiveRecord::AssociationTypeMismatch: Connector(#70297711668780) expected, got Hash(#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))

【问题讨论】:

标签: ruby-on-rails ruby json activerecord grape


【解决方案1】:

在您的模型Card 中,您创建了一个名为connectors 的关联。这是一个ActiveRecord::Relation 方法,它将期待来自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

【讨论】:

  • 好回答豪尔赫! :) 我明白为什么会出现错误,但不知道如何处理。关于您的第二个建议的问题,如果我在哪里重新定义 intialize 方法,这是否会迫使我始终使用哈希来创建我的模型?
  • 两个答案都告诉您如何处理错误。只需复制代码,您应该至少会收到一个新错误。您总是需要一个哈希来创建模型。 initiaze(params={}) 是用于初始化的活动模型默认值。
【解决方案2】:

您可以使用来自ActiveSupport 的标准 JSON 解码,这将为您提供一个哈希值。

然后您需要从该哈希中构建一个新的 ActiveRecord 对象。

my_object = Foo.new(ActiveSupport::JSON.decode(some_json))

如果您希望将create 保存在一行中,请将new 换成create

【讨论】:

  • 好的,当我的模型只有简单的类型(如 int 或 string)时,效果很好。如果我的模型包含与其他 ActiveRecord 模型的关联,我会收到以下错误,其中 Connector 是关联 ActiveRecord 类的名称:ActiveRecord::AssociationTypeMismatch: Connector(#70114314283600) expected, got Hash(#70114301340420)
  • @Abris 你能在你的问题中包含一个示例 json 吗
  • 更新了一个例子
  • 那是因为您使用连接器作为哈希和关联中的键,但您没有初始化它。尝试将连接器键重命名为 connector_attributes
  • @JorgedelosSantos 那也需要accepts_nested_attributes_for :connectors 吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多