如何在使用as_json时干掉Rails / ActiveRecord?

时间:2013-03-09 20:01:22

标签: ruby-on-rails json ruby-on-rails-3 activerecord ruby-on-rails-3.2

假设以下关系:

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
)

但是当我想以:only格式使用:exceptas_json时,它会变得复杂。


我如何干这些包括,最好只宣布一次关系格式?

也许有一些方法可以利用命名范围或某些宝石?

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

您可以覆盖模型中的as_json方法

例如

class Blog < ActiveRecord::Base

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

然后你的控制器看起来像

render json: @blogs

<强>建议

您可以使用JBuilder,Rabl,AMS或其他模板库,这些模板库允许您将响应构建从控制器/模型逻辑中分离出来。这样做肯定会干掉你的代码。