2013-10-26 46 views
0

我有一个Item类也包含很多项目(使用has_many)。我想要做的是读取所有没有父项(顶层)的项目及其所有子项目。所以基本上我需要将我的整个Item表正确嵌套到json中。Rails to_json与所有关系

这是我现在正在使用的代码,但这只返回最高级别的项目和它们的项目,它不会低于此值。 (所以我只剩下两个级别)

@items = Item.where("item_id IS ?" , nil).order("position") 
respond_to do |format| 
    format.json { render :json => @items.to_json(:include => :items)} 
end 
+0

你知道Rabl的宝石?我认为你可以使用它。 https://github.com/nesquena/rabl –

+0

物品类也包含很多物品? – shiva

+0

@shiva是的。所以基本上每个项目我都可以做Item.first.items – networkprofile

回答

2

不建议覆盖as_json或to_json

原因是你需要其他地方的原始数据,你可能需要其他格式的数据。操纵as_json将最终更改数据,并且您无法扩展。

使用装饰器是要走的路。一个不错的选择宝石ActiveModel Serializers。基本上,它像这样工作

class ItemSerializer < ActiveModel::Serializer 
    attributes :id, :title, :body 
    has_many :comments # The JSON output will have comments inside. 
end 

然后在你的控制器:

@items = Item.where("item_id IS ?" , nil).order("position") 
respond_to do |format| 
    format.json { render :json => @items } 
end 

@items将ItemSerializer自动序列化。

或者你可以选择自定义序列

render json: @items, each_serializer: ItemWithAssociatedSerializer 
+1

重写'as_json'就像我改变默认值,所以你可以通过传递'to_json'参数来回到以前的行为。无论如何,使用序列化器更好(我用as_json,因为这是官方推荐的方法),所以你是对的:) –

1

首先,我会建议使用宝石像ancestryawesome nested set。它将帮助您有效地管理您的Items树结构(在一个SQL查询中检索整个层次结构,等等)。

那么你可以做这样的事情:

class Item 
    def as_json(options={}) 
    super({include: items}.merge options) 
    end 
end 

这意味着呼吁to_json上的项目会被默认包括孩子们的JSON;所以递归地我们走下整个层次结构。

如果您需要一种方法来限制嵌套的级别数,你可以这样做:

class Item 
    def as_json(options={}) 
    return super({include: items}.merge options) unless options[:depth].present? 
    if options[:depth] > 0 
     super({include: items, depth: options[:depth] - 1}.merge options) 
    else 
     super 
    end 
    end 
end 
+0

这似乎不起作用(或者我需要先安装宝石?)实际上是我的应用程序中唯一的这种情况,我不需要太多的选择,但如果它们让生活更轻松,我会查看那些宝石。谢谢! – networkprofile

+0

对不起,没有测试过。什么不行?第一个还是第二个解决方案? –

+0

哎呀,错字。 '包括'=>''包括' –