1

假设以下关系:如何使Rails/ActiveRecord在使用as_json时包括在内?

Blog的has_many Posts的has_many Comments HAS_ONE Author

如果我要得到所有Blogs所有Posts,我可以这样写:

Blog.all.as_json(:include => :posts) 

然而,这将导致N + 1查询。

所以不是我需要写:

Blog.includes(:posts).all.as_json(:include => :posts) 

预期其中一期工程,但不是很干,尤其是当你有嵌套包括。

例如:

Blog.includes(
    :posts => { 
     :comments => :author 
    } 
).all.as_json(
    :include => { 
     :posts => { 
      :include => { 
       :comments => { 
        :include => :author 
       } 
      } 
     } 
    } 
) 

,当我需要查询在多个地点此相同的JSON格式,这个问题变得更糟。

我想过把as_json关系格式类方法,像这样:

class Blog < ActiveRecord::base 
... 
    def self.include_all_json_format 
    :include => { 
     :posts => { 
      :include => { 
       :comments => { 
        :include => :author 
       } 
      } 
     } 
    } 
    end 
... 
end 

解决了查询多个位置的这个JSON格式的问题,因为我可以那么就使用:

Blog.includes(
    :posts => { 
     :comments => :author 
    } 
).all.as_json(
    Blog.include_all_json_format 
) 

但当然Blog.includes()需要为它关系哈希不同的格式,所以这样的:

Blog.includes(
    Blog.include_all_json_format 
).all.as_json(
    Blog.include_all_json_format 
) 

不起作用。

我可以把Blog.includes()关系散列放在第二个类方法中,但是有两个方法声明相同包含结构不是DRY。


我现在能想到的是使用上述Blog.include_all_json_format方法,然后编写可以反过来说,关系散列到通过Blog.includes()期望的格式(转换器方法的唯一想法基本上只是剥出:include键),所以它可以被称为:

Blog.includes(
    MyConverter(Blog.include_all_json_format) 
).all.as_json(
    Blog.include_all_json_format 
) 

但后来情况就变得复杂时,我想在我的as_json格式使用:only:except


我该如何干这些包括起来,最好只声明关系格式一次?

也许有一些方法来使用命名的范围或一些宝石?

任何帮助,非常感谢。

+0

你可以尝试[deep_pluck](https://github.com/khiav223577/deep_pluck)来烘干它。 – 2017-03-30 13:24:01

回答

0

可以重写as_json方法模型

例如

class Blog < ActiveRecord::Base 

    def as_json 
    super(:include => :posts) 
    end 
end 

那么你的控制器看起来应该像

render json: @blogs

建议

您可以使用JBuilder,Rabl,AMS或其他模板库,以便将响应构建在控制器/模型逻辑之外。这样做肯定会干掉你的代码。

+0

感谢您的回复。重写'as_json'将与Blog.all.as_json(:include =>:posts)相同,但是,是正确的?因此仍然会产生低效率的N + 1查询。我会检查这些图书馆,谢谢。 – Marc 2013-03-09 20:47:32

+0

我认为整个问题是,你应该从你的控制器逻辑中分离你的“视图”模板。就像'@blog = Blog.includes(:posts).all'然后'render json:@ blog'一样,不用调用as_json,但仍然按照我向你展示的方式覆盖它,将会干掉它并防止N + 1查询。 – 2013-03-09 21:23:37