Rails API:as_json with includes查询数据库,尽管之前包含



我正在努力寻找呈现记录的最佳方式。到目前为止,我是按照以下方式完成的,但是,尽管在获取主对象时有include,但在为包含的子记录调用as_json时,我会收到大量的DB查询。我错过了什么?还有更好的方法做我想做的事吗?

我不知道如何进行更好的渲染,因为我想决定在关联记录的数组上串行化和使用自定义范围的属性和方法。

  • 我的控制器
def show
# The include below seems to be useless, the DB is queried again on render.
@grandParent = GrandParent.includes(parents: { children: %i[grand_children friends] })
.find_by_name(params[:name])
return head :not_found unless @grandParent
render json: grand_parent_as_json, status: :ok
end
private
def grand_parent_as_json
json = @grandParent.as_json(
only: %i[attr1 attr2],
methods: %i[meth1 meth2]
)
# I don't see a better way to render it since I want to use a custom scope on parents
json[:parents] = @grandParent.parents.ordered_by_birthdate(:desc).map do |parent|
parent_as_json parent
end

json
end
# The include below seem to be the one responsible for querying the DB again.
def parent_as_json(parent)
parent.as_json(
only: %i[attr1 attr2],
methods: %i[meth1 meth2],
include: [
children: {
only: %i[attr1 attr2],
include: [
grand_children: { %i[attr1 attr2] }
]
}
]
)
end

很确定有一种更优雅的方法可以解决这个问题,但问题确实是这里使用的范围:

@grandParent.parents.ordered_by_birthdate(:desc)

原因是作用域保证返回一个新的ActiveRecord::Relation,当访问该关系时,它会命中DB。

这可能不是最好的答案,但它可以通过更改初始查询来工作,在birthdate字段中包含.order

@grandParent = GrandParent
.includes(parents: { children: %I[grand_children friends] })
.order("parents.birthdate DESC")
.find_by_name(params[:name])

然后在映射父对象时移除.ordered_by_birthdate,因为它们已经按照您想要的顺序排列。这具有不使用在Parent上定义的范围ordered_by_birthdate的缺点。这可能是可以的,取决于您如何看待控制器和模型的责任。

或者,上述代码片段也可以是GrandParent范围的一部分,例如

class GrandParent
scope :family_tree, -> { includes(parents: { children: %I[grand_children friends] }).order("parents.birthdate DESC") }
end

然后你可以做:

GrandParent.family_tree.find_by_name(params[:name])

相关内容

  • 没有找到相关文章

最新更新