我的Ruby on Rails API中有深度关联的模型,有时深层次有4个关联。例如:
Group has_many Subgroups has_many: Posts has_many: Comments
如果我想回复Group.title
我的评论,我需要说:
@comment.post.subgroup.group.title
由于这是每个Comment的查询太多,我在Comment表中添加了一个名为group_title的列。创建注释时将分配此属性。然后每次更新关联的Group.title时,我在Group模型上都有一个after_update方法来更新所有关联的Comment group_titles。
这对我来说似乎很多代码,我发现自己经常在这个大型应用程序中这样做。有没有办法将这两个属性链接在一起,以便每次更新其关联的Group.title时自动更新Comment.group_title?
答案 0 :(得分:0)
我也有类似的关系层次结构,并用连接解决了它(可能有更好的解决方案)。
Quarter
belongs_to Detour
belongs_to Forestry
belongs_to Region
对于给定的绕道,我找到一个查询的区域名称。
Quarter.select("regions.name AS region_name, forestries.name as forestry_name, \
detours.name AS detour_name, quarters.*")
.joins(detour: [forestry: :region])
当然,您可以将其封装在范围内。
class Quarter
...
scope :with_all_parents, -> {
select("regions.name AS region_name, forestries.name as forestry_name, \
detours.name AS detour_name, quarters.*")
.joins(detour: [forestry: :region])
}
end
您也可以使用相同的方法。
class Comment
...
scope :with_group_titles, -> {
select("groups.title AS group_title, comments.*").joins(post: [subgroup: :group])
}
end
答案 1 :(得分:0)
您可以使用间接关联构建层次结构:
class Group
has_many :subgroups
has_many :posts, through: :subgroups
has_many :comments, through: :posts
end
class Subgroup
belongs_to :group
has_many :posts
has_many :comments, through: :posts
end
class Post
belongs_to :subgroup
has_one :group, through: :subgroup
has_many :comments
end
class Comment
belongs_to :post
has_one :subgroup, through: :post
has_one :group, through: :post
end
这允许你从任何一端开始,铁路将为你处理加入。
例如,你可以这样做:
@comment.group.title
或者在没有传递嵌套哈希的情况下进行预先加载:
@comment = Comment.eager_load(:group).find(params[:id])
然而,这并未完全解决与加入深层嵌套层次结构相关的性能问题。这仍然会在四个桌子上产生一个连接的怪物。
如果要在comments
表格上缓存标题,可以使用ActiveRecord回调,也可以定义database trigger procedure。
class Group
after_save :update_comments!
def update_comments!
self.comments.update_all(group_title: self.title)
end
end
答案 2 :(得分:0)
您可以通过更新一方的所有评论来完成此操作。
class Group
after_update do
Comment.joins(post: [subgroup: :group]).where("groups.title=?", self.title).update_all(group_title: self.title)
end
end