我正在努力寻找呈现记录的最佳方法。到目前为止,我是通过以下方式完成的,但是,尽管在获取主对象时包含了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,当访问该ActiveRecord :: Relation时会到达数据库。
它可能不是最佳答案,但可以通过更改您的初始查询(包括.order
forbirthdate
字段)来工作。
@grandParent = GrandParent
.includes(parents: { children: %I[grand_children friends] })
.order("parents.birthdate DESC")
.find_by_name(params[:name])
然后.ordered_by_birthdate
,在映射父对象时将其删除,因为它们已经按照您想要的顺序排列了。这样做的缺点是不使用ordered_by_birthdate
定义的范围Parent
。这可能是可以的,具体取决于您如何查看控制器与模型的职责。
另外,上述代码段也可以是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])
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句