如何在rails中显示其子记录总数的父记录

时间:2017-12-15 07:05:19

标签: ruby-on-rails parent-child counter-cache

class Attachment < ActiveRecord::Base
  belongs_to :user, foreign_key: :creator_id
  belongs_to :deal_task, foreign_key: :relation_id
end
class DealTask < ActiveRecord::Base
   has_many :attachments, foreign_key: :relation_id
end

我有名为DealTask​​的父表和名为Attachment的子表

我想要一个DealTask​​记录列表以及相关的附件总数

4 个答案:

答案 0 :(得分:1)

DealTask.all.map do |deal_task|
  deal_task.
    attributes.
    with_indifferent_access.
    slice(:id, :name).
    merge!(total_attachment: deal_task.attachments.count)
end

或者,如果您不关心无关紧要的访问权限,并且您不介意拥有所有DealTask属性,那么您可以在一行中写下这一点:

DealTask.all.map{|deal_task| deal_task.attributes.merge!(total_attachments: deal_task.attachments.count)}

打破它......

DealTask.all.map do |deal_task|
  ...
end

将返回arrayarray将包含do块的结果。

deal_task.
  attributes.
  with_indifferent_access

为您提供可以使用deal_taskstrings访问的哈希中每个symbols的属性(因此,&#34; indifferent_access&#34;)。

deal_task.
  attributes.
  with_indifferent_access.
  slice(:id, :name)

仅保留:id哈希的:namedeal_task

merge!(total_attachments: deal_task.attachments.count)

使用键total_attachments将附件计数添加到您的哈希。

结果应该类似于:

[
  {id: 1, name: 'name1', total_attachments: 12},
  {id: 2, name: 'name2', total_attachments: 3}
]

答案 1 :(得分:0)

试试这个

DealTask.all.map { |deal_task| deal_task.attachments.ids }.count

答案 2 :(得分:0)

isLocalNotification

DealTask.first.attachments.count #This will give count of attachemenets

或者

#To show all records and all the count

DealTask.find_each do |dt|
      print dt.inspect
      print "\n"
      print dt.attachments.count
end

格式更好

DealTask.joins(:attachments).select("deal_tasks.*, count(attachements.id) as count").group("deal_tasks.id")

当您在单个查询中获取所有数据时,这将快得多

答案 3 :(得分:0)

我找到了父母子女关系计数的最佳解决方案

counter_cache: true

因为以上所有查询都需要花费太多时间从数据库加载

所以你们都喜欢使用这个

1→在名为 DealTask​​

父表中添加一列
rails g migration AddAttachmentsCountToDealTask attachments_count:integer

2→打开迁移添加编辑

class AddAttachmentCountToDealTask < ActiveRecord::Migration[5.0]

 def up
  add_column :deal_tasks, :attachments_count, :integer, default: 0
  DealTask.reset_column_information
  DealTask.find_each do |deal_task|
    DealTask.reset_counters deal_task.id, :attachments
  end
 end
 def down
  remove_column :deal_tasks, attachments_count
 end
end

因此,当您回滚迁移时,它不会引发错误或异常

您也可以使用任何循环而不是使用

find_each, DealTask.all.each do...end

但是,是的,重置计数器必须使用类名称

DealTask.reset_counters

3→设置计数器缓存

class Attachment < ActiveRecord::Base
 belongs_to :deal_task, foreign_key: :relation_id, counter_cache: true
end
class DealTask < ActiveRecord::Base
 has_many :attachments, foreign_key: :relation_id
end

假设您的模型名称 sub_tasks ,而您的counter_cache列必须

sub_tasks_count

如果您需要自己的列名,则必须在counter_cache中指定该列名

假设列名是total_subtasks而不是

belongs_to :deal_task, foreign_key: :relation_id, counter_cache: :total_subtasks

并相应地进行更改以更新counter_cache

现在当您添加任何附件时, attachments_count 列增加1,这将由** counter_cache自动完成

有一个问题 **当你删除任何一个孩子时,counter_cache无法减少**

因此该解决方案进行回调

class Attachment < ActiveRecord::Base
 belongs_to :deal_task, foreign_key: :relation_id, counter_cache: true
 before_destroy :reset_counter
 private
 def reset_counter
  DealTask.reset_counters(self.relation.id, :attachments)
 end
end

因此,当您删除任何附件时,它将通过 relation_id 重置其父项的countet_cache,即parent_id或附件的Foreign_key

了解更多信息 观看Railscast counter cache 23

上的视频