如何在 rails 中显示父记录及其子记录总数
How to display Parent record with total number of its Child record in rails
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
我的父 table 称为 DealTask,子 table 称为 Attachment
我想要一个包含相关附件总数的 DealTask 记录列表
试试这个
DealTask.all.map { |deal_task| deal_task.attachments.ids }.count
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")
为了更好的格式
DealTask.joins(:attachments)
.select("deal_tasks.id, deal_tasks.name, count(attachements.id) as attachments")
.group("deal_tasks.id")
.collect(&:attributes)
#This will gve you something like
[
{"id"=>34332630, "name"=>"some name", "attachments"=>1},
{"id"=>71649461, "name"=>"some name", "attachments"=>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
即将 return 和 array
。 array
将包含 do
块的结果。
deal_task.
attributes.
with_indifferent_access
为您提供散列中每个 deal_task
的属性,可以使用 strings
或 symbols
访问(因此,"indifferent_access")。
deal_task.
attributes.
with_indifferent_access.
slice(:id, :name)
仅保留 deal_task
散列的 :id
和 :name
。
merge!(total_attachments: deal_task.attachments.count)
使用键 total_attachments
.
将附件计数添加到您的散列中
结果应该类似于:
[
{id: 1, name: 'name1', total_attachments: 12},
{id: 2, name: 'name2', total_attachments: 3}
]
我找到了 Parent child 关系数
的最佳解决方案
counter_cache: true
因为上述所有查询都需要太多时间从数据库加载
所以你们一定更喜欢用这个
1-> 在 Parent table 中添加一列称为 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
但是是的,虽然 重置计数器 必须使用 class 名称,如
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
自动完成的
有一个问题
**当你删除任何child时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 为它的 Parent 重置 countet_cache,即 parent_id 或Foreign_key 附件
了解更多信息
在 Railscast counter cache 23
上观看视频
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
我的父 table 称为 DealTask,子 table 称为 Attachment
我想要一个包含相关附件总数的 DealTask 记录列表
试试这个
DealTask.all.map { |deal_task| deal_task.attachments.ids }.count
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")
为了更好的格式
DealTask.joins(:attachments)
.select("deal_tasks.id, deal_tasks.name, count(attachements.id) as attachments")
.group("deal_tasks.id")
.collect(&:attributes)
#This will gve you something like
[
{"id"=>34332630, "name"=>"some name", "attachments"=>1},
{"id"=>71649461, "name"=>"some name", "attachments"=>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
即将 return 和 array
。 array
将包含 do
块的结果。
deal_task.
attributes.
with_indifferent_access
为您提供散列中每个 deal_task
的属性,可以使用 strings
或 symbols
访问(因此,"indifferent_access")。
deal_task.
attributes.
with_indifferent_access.
slice(:id, :name)
仅保留 deal_task
散列的 :id
和 :name
。
merge!(total_attachments: deal_task.attachments.count)
使用键 total_attachments
.
结果应该类似于:
[
{id: 1, name: 'name1', total_attachments: 12},
{id: 2, name: 'name2', total_attachments: 3}
]
我找到了 Parent child 关系数
的最佳解决方案counter_cache: true
因为上述所有查询都需要太多时间从数据库加载
所以你们一定更喜欢用这个
1-> 在 Parent table 中添加一列称为 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
但是是的,虽然 重置计数器 必须使用 class 名称,如
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
自动完成的有一个问题 **当你删除任何child时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 为它的 Parent 重置 countet_cache,即 parent_id 或Foreign_key 附件
了解更多信息 在 Railscast counter cache 23
上观看视频