Rails as_json问题 - 如何有效地包含嵌套对象?

时间:2012-04-26 19:36:55

标签: ruby-on-rails ruby ruby-on-rails-3

我遇到了一个我正在使用as_json方法的问题,以及如何在JSON 中有效地返回对象和它的belongs_to对象也是JSON,其中belongs_to对象具有它自己的belongs_to对象。代码可能会更好地解释它。

不工作方式

警报类

class Alert < ActiveRecord::Base
    belongs_to :message
    # for json rendering
    def as_json(options={})
        super(:include => :message)
    end
end

消息类

 def as_json(options={})
    super( methods: [:timestamp, :num_photos, :first_photo_url, :tag_names],
           include: { camera: { only: [:id, :name] },
                      position: { only: [:id, :name, :address, :default_threat_level ]},
                      images: { only: [:id, :photo_url, :is_hidden]} })
  end

第一次设置的问题是当我有一个Alert对象并调用

alert.as_json()

我从Alert中获取了所有属性,并从Message中获取了所有属性,但是没有来自Message的其他属性,如Camera,Position等。

这是“它正在工作,但可能不是正确的设计方式”

警报类

class Alert < ActiveRecord::Base

    belongs_to :message

    # for json rendering
    def as_json(options={})
        super().merge(:message => message.as_json)
    end
end

消息类

  # for json rendering
  def as_json(options={})
    super( methods: [:timestamp, :num_photos, :first_photo_url, :tag_names])
          .merge(:camera => camera.as_json)
          .merge(:position => position.as_json)
          .merge(:images => images.as_json)
  end

在第二个设置中,我得到了所有Message的嵌套属性,就像我想要的那样。

我的问题是,我是否错过了一些适当的Rails公约?似乎会有/应该是一种更容易的方式。

3 个答案:

答案 0 :(得分:7)

对我来说最好的答案是使用serializable_hash。 @kikito在他的评论中提到了这一点,但有一个错字阻止它工作。它不是serialized_hash,而是serializable_hash

直接找到+ as_json替换serializable_hash,这个错误消失了。 (它仍未在今天的Rails 4.0.2中修复)。您还可以获得以后更轻松地实现XML API的好处(有些人仍然使用它们!)。

答案 1 :(得分:3)

您使用的是哪个版本的Rails?这是旧版Rails中的一个已知错误,据称已使用this pull request修复。你的语法看起来对我来说,也许这是你的问题?

顺便说一句,您可能还想从Jose Valim(Rails核心成员)签出新的active_model_serializers。它可能至少使您能够以更优雅的方式解决您的问题。

答案 2 :(得分:1)

我建议你看一下RABL(代表Ruby API Builder语言)gem(railscastgithub)。它为您提供了一个DSL,用于在模板中定义JSON(以及XML)响应的结构(如Haml或CoffeeScript)。它还支持部分内容。