1

假设以下关系:

Bloghas_many Postshas_many Commentshas_oneAuthor

如果我想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:except以我的as_json格式使用时,它会变得复杂。


我怎样才能干燥这些包括,最好只声明一次关系格式?

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

任何帮助是极大的赞赏。

4

1 回答 1

0

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

例如

class Blog < ActiveRecord::Base

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

然后你的控制器应该看起来像

render json: @blogs

建议

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

于 2013-03-09T20:10:50.643 回答