将虚拟属性添加到json输出

时间:2011-07-31 20:16:35

标签: ruby-on-rails json

假设我有一个处理TODO列表的应用程序。该清单已完成和未完成的项目。现在我想向列表对象添加两个虚拟属性;列表中已完成和未完成的项目数。我还需要在json输出中显示它们。

我的模型中有两个方法可以获取未完成/已完成的项目:

def unfinished_items 
  self.items.where("status = ?", false) 
end 

def finished_items 
  self.items.where("status = ?", true) 
end

那么,我怎样才能在json输出中得到这两个方法的计数?

我正在使用Rails 3.1

8 个答案:

答案 0 :(得分:107)

Rails中对象的序列化有两个步骤:

  • 首先,调用as_json将对象转换为简化的哈希。
  • 然后,在to_json返回值上调用as_json以获取最终的JSON字符串。

您通常希望单独留下to_json,这样您只需添加your own as_json implementation,就像这样:

def as_json(options = { })
  # just in case someone says as_json(nil) and bypasses
  # our default...
  super((options || { }).merge({
    :methods => [:finished_items, :unfinished_items]
  }))
end

你也可以这样做:

def as_json(options = { })
  h = super(options)
  h[:finished]   = finished_items
  h[:unfinished] = unfinished_items
  h
end

如果您想为方法支持的值使用不同的名称。

如果您关心XML和JSON,请查看serializable_hash

答案 1 :(得分:27)

使用Rails 4,您可以执行以下操作 -

render json: @my_object.to_json(:methods => [:finished_items, :unfinished_items])

希望这可以帮助那些处于后期/最新版本的人

答案 2 :(得分:15)

另一种方法是将此添加到您的模型中:

def attributes
  super.merge({'unfinished' => unfinished_items, 'finished' => finished_items})
end

这也可以自动用于xml序列化。 http://api.rubyonrails.org/classes/ActiveModel/Serialization.html 但请注意,您可能需要为键使用字符串,因为在对rails 3中的键进行排序时,该方法无法处理符号。但它不会在rails 4中排序,因此不应再出现问题。

答案 3 :(得分:3)

将所有数据关闭到一个哈希,例如

render json: {items: items, finished: finished, unfinished: unfinished}

答案 4 :(得分:1)

我只是觉得我会为像我这样的人提供这个答案,他试图将其整合到现有的 as_json 块中:

  def as_json(options={})
    super(:only => [:id, :longitude, :latitude],
          :include => {
            :users => {:only => [:id]}
          }
    ).merge({:premium => premium?})

.merge({})放在super()

的末尾

答案 5 :(得分:1)

如上面列出的Aswin:methods将使您能够将特定模型的方法/函数作为json属性返回,如果您有复杂的关联,这将会起到作用,因为它将添加函数现有的模型/对象:如果您不想重新定义as_json

,它将像魅力一样工作

检查此代码,请注意我如何使用:methods以及:include [N +查询甚至不是一个选项;)

render json: @YOUR_MODEL.to_json(:methods => [:method_1, :method_2], :include => [:company, :surveys, :customer => {:include => [:user]}])

在这种情况下,覆盖as_json功能将更加困难(特别是因为您必须手动添加:include点击:/ def as_json(options = { }) end

答案 6 :(得分:0)

这样做,而不必做一些丑陋的覆盖。例如,如果你有一个模型(12,6,6) -> 1 (1,0,6) -> 1 (2,3,7) -> 0 ,你可以把它放在你的控制器中:

List

答案 7 :(得分:0)

如果你想用它们的虚拟属性渲染一组对象,你可以使用

render json: many_users.as_json(methods: [:first_name, :last_name])

其中 first_namelast_name 是定义在模型上的虚拟属性