Ruby on Rails:是否可以将列与另一个表上的列链接?

时间:2017-10-30 06:49:23

标签: ruby-on-rails ruby

我的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?

3 个答案:

答案 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
相关问题