Rails to_json与所有关系

时间:2022-12-31 23:20:43

I have an Item class that also contains many items (using has_many). What I want to do is read all items that have no parent (the top level) and all their subitems. So basically I need my entire Item table nested correctly, into json.

我有一个Item类,它还包含许多项(使用has_many)。我想要做的是阅读所有没有父级(*)及其所有子项的项目。所以基本上我需要将我的整个Item表正确嵌套到json中。

This is the code I'm using right now, but this only returns the top level items and their items, it doesn't go any lower than that. (So I'm left with only two levels)

这是我现在正在使用的代码,但这只返回*项目及其项目,它不会低于此值。 (所以我只留下两个级别)

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

2 个解决方案

#1


2  

I do not suggest override as_json or to_json.

我不建议覆盖as_json或to_json。

The reason is you'll need the raw data elsewhere, and you may need data in other format. Manipulate as_json will finally change the data, and you have no way to extend.

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

Using a decorator is the way to go. A good choice the gem ActiveModel Serializers. Basically it work like this

使用装饰器是可行的方法。宝石ActiveModel Serializers是一个不错的选择。基本上它就像这样工作

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

And then in your controller:

然后在你的控制器中:

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

Your @items will be serialized by ItemSerializer automatically.

您的@items将自动由ItemSerializer序列化。

Or you can choose a custom serializer

或者您可以选择自定义序列化程序

render json: @items, each_serializer: ItemWithAssociatedSerializer

#2


1  

First, I would recommend using a gem like ancestry or awesome nested set. It will help you manage your Items tree structure efficiently (retrieving a whole hierarchy in one SQL query, and so on).

首先,我建议使用像祖先或真棒嵌套集的宝石。它将帮助您有效地管理Items树结构(在一个SQL查询中检索整个层次结构,等等)。

then you can do something like this :

然后你可以做这样的事情:

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

this means that calling to_json on an item would by default include the children's json ; so recursively we go down the whole hierarchy.

这意味着在项目上调用to_json默认包含子项的json;所以递归地我们沿着整个层次结构走下去。

If you need a way to limit the number of nested levels, you can do :

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

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

#1


2  

I do not suggest override as_json or to_json.

我不建议覆盖as_json或to_json。

The reason is you'll need the raw data elsewhere, and you may need data in other format. Manipulate as_json will finally change the data, and you have no way to extend.

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

Using a decorator is the way to go. A good choice the gem ActiveModel Serializers. Basically it work like this

使用装饰器是可行的方法。宝石ActiveModel Serializers是一个不错的选择。基本上它就像这样工作

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

And then in your controller:

然后在你的控制器中:

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

Your @items will be serialized by ItemSerializer automatically.

您的@items将自动由ItemSerializer序列化。

Or you can choose a custom serializer

或者您可以选择自定义序列化程序

render json: @items, each_serializer: ItemWithAssociatedSerializer

#2


1  

First, I would recommend using a gem like ancestry or awesome nested set. It will help you manage your Items tree structure efficiently (retrieving a whole hierarchy in one SQL query, and so on).

首先,我建议使用像祖先或真棒嵌套集的宝石。它将帮助您有效地管理Items树结构(在一个SQL查询中检索整个层次结构,等等)。

then you can do something like this :

然后你可以做这样的事情:

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

this means that calling to_json on an item would by default include the children's json ; so recursively we go down the whole hierarchy.

这意味着在项目上调用to_json默认包含子项的json;所以递归地我们沿着整个层次结构走下去。

If you need a way to limit the number of nested levels, you can do :

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

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