通过counter_cache使用has_many :through

25

据我所知,当定义:counter_cache选项时,应在包含belongs_to声明的模型上指定。因此,当使用has_many through关联时,我有些不确定该如何处理(因为我认为在这种情况下不使用belongs_to声明):

class Physician < ActiveRecord::Base
  has_many :appointments
  has_many :patients, :through => :appointments
end

class Appointment < ActiveRecord::Base
  belongs_to :physician, :counter_cache => appointment_count
end

class Patient < ActiveRecord::Base
end

我希望使用:counter_cache选项来使查找属于医生的患者数量更加高效。

myPhysician.patients.count

提醒一下:Rails 3.1

干杯

4个回答

33

我不确定你想要哪种关系。那个示例类似于Rails指南中的一个示例。

class Physician < ActiveRecord::Base
  has_many :appointments
  has_many :patients, :through => :appointments
end

class Appointment < ActiveRecord::Base
  belongs_to :physician
  belongs_to :patient
end

class Patient < ActiveRecord::Base
  has_many :appointments
  has_many :physicians, :through => :appointments
end
  • Physician拥有许多Appointments,也拥有许多Patients
  • Appointment属于(拥有)一个Physician和一个Patient
  • Patient拥有许多Appointments和许多Physicians

关于:counter_cache选项,根据belongs_to文档: 如果你想知道属于一个PhysicianPatients数量,你需要:

class Appointment < ActiveRecord::Base
  belongs_to :physician, :counter_cache => :patient_count
  belongs_to :patient
end

你需要编写一个迁移脚本,向Phyisicans表中添加patient_count列。

但是,在Rails 3.1中,对于has_many through关系,似乎会自动检测到计数器缓存列,所以你不必指定它(删除:counter_cache => :patient_count)。如果你指定了它,你的计数器将增加两次(这非常奇怪)。

顺便说一下,在Rails 3.1中,:counter_cache选项存在一些问题,如此处所述:

考虑到所有这些,也许你最好的选择是使用回调函数编写自己的计数机制。

希望能有所帮助 :)


12
最新消息:Rails框架已经取消了自动检测“has_many :through”的计数缓存功能。具体信息请参见以下链接:https://github.com/sgrif/rails/commit/f072980382db8cb64c09f63001ef805843db51c8 - head
我不明白为什么这个答案会得到这么多赞;每次创建新的预约时,这将增加“Physician#patient_count”,这不是我们想要的。如果一个患者与同一位医生有5个预约,那么该患者将被重复计算为5个患者,每个预约一个。 - sandre89

10

我在Rails 5.1上的has_many :through关联中添加了counter_cache,其哲学与has_many相同。 使用Physician、Appointment、Patient示例:

  1. 将一个名为patients_count的整数添加到physicians表中
  2. 在连接模型中(appointment.rb)添加计数器缓存:belongs_to :physician, counter_cache: :patients_count

注意: 上面的答案是正确的,这个答案只是确认它在Rails 5.1上可以工作。


1
我遇到了类似的问题,需要计算两层关系中的记录数。在您的示例中,这将是医生的患者数量,而不是预约数量。(例如,不要计算一个患者的多个预约) 我没有测试其他提供的解决方案,但它们似乎返回预约的数量。
我在Rails 4中找不到解决方法,主要是因为没有 belongs_to through:选项。经过尝试了几种无果的方法后,我发现了gem counter_culture。通过定义要计数的两层关系,这很容易解决问题:
class Patient < ActiveRecord::Base
  belongs_to :appointment
  counter_culture [:appointment, :physician]
end

在医生模型中添加一个计数器字段,具体操作如下:

rails generate counter_culture Physician patients_count

看这里!现在您可以轻松进行类似于activerecord的查询,例如:

Physician.order(patients_count: 'DESC')

0

我可以确认Ivica Lakatos提出的方法适用于Rails 6中使用联结模型的has_many :through关系。

  1. 将patients_count作为整数添加到physicians表中
  2. 在联结模型(appointment.rb)中添加计数器缓存: belongs_to :physician, counter_cache: :patients_count

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接