Ruby on rails 避免N+;1在模型实例方法中使用sort_by代替order

Ruby on rails 避免N+;1在模型实例方法中使用sort_by代替order,ruby-on-rails,Ruby On Rails,我的应用程序是一个面向教师的CRM,其中一名教师属于一个帐户,该帐户拥有许多学生,他们通过CallablePhoneNumber拥有TM电话号码(因为IRL兄弟姐妹可以共享一个电话号码) (旁白:作为一个可能的复杂因素,电话号码是多态的。教师和学生都是“可呼叫的”。) 我的问题:我试图在学生列表视图中避免N+1。当查看900名学生的名单和一些元数据时,数据库的点击率非常可怕 app/models/student.rb class Student < ActiveRecord::Base

我的应用程序是一个面向教师的CRM,其中一名教师属于一个帐户,该帐户拥有许多学生,他们通过CallablePhoneNumber拥有TM电话号码(因为IRL兄弟姐妹可以共享一个电话号码)

(旁白:作为一个可能的复杂因素,电话号码是多态的。教师和学生都是“可呼叫的”。)

我的问题:我试图在学生列表视图中避免N+1。当查看900名学生的名单和一些元数据时,数据库的点击率非常可怕

app/models/student.rb

class Student < ActiveRecord::Base

  ...

  has_many :phone_numbers, through: :callable_phone_numbers, as: :callable_phone_numbers

  ...

  def last_messaged_at
    self.phone_numbers.order(:last_received_message_at).last.try(:last_received_message_at)
    # :last_received_message_at is a simple DateTime in the database
  end

  ...

end
class DashesController < ApplicationController
  before_action :logged_in_teacher

  def show
    @teacher = Teacher.includes(account: [{students: [:phone_numbers, :grade_level, :student_groups]}, :grade_levels]).includes(:student_groups).find(@current_teacher.id)
  end

end
当我以为那些电话号码已经在内存中时,我意外地被迫再次ping数据库


我觉得一个实例方法最适合于此,但也许它应该是我将电话号码集合传递给的助手?即使是这样,我仍然不清楚为什么实例方法无法“查看”加载的电话号码。

如果您已经急切地加载了关联,请尝试
按排序

self.phone_numbers.sort_by { |pn| pn.last_received_message_at || Time.now - 20.year }.last.try(:last_received_message_at)

我认为您的ordering子句
order(:last_received_message_at)
在重新发送查询的方法中。你能试着从方法中删除那个order子句,看看它是否仍然是一个单独的查询吗。但是,.order()逻辑是必需的(因为最后创建的可能不是最近发送的消息)。而且,它实际上并没有阻止额外的查询。这会有帮助的
self.phone\u number.sort\u by{pn | pn.last\u received\u message\u at}.last.try(:last\u received\u message\u at)
按住电话。事实上,我有工作要做。(我还必须在sort|u by block中添加一个额外的catch all来解决nils。我不确定昨天到底做了什么导致我得到了重新查询,但我现在是golden了。
self.phone_numbers.sort|u by{pn | pn.last| u在| Time.now-20.year}.最后尝试(:last| u received|message|at)
如果您将此作为回答添加到下面,我很乐意接受。:)
pry(main)> t.account.students.first.last_messaged_at
  PhoneNumber Load (0.4ms)  SELECT  "phone_numbers".* FROM "phone_numbers" INNER JOIN "callable_phone_numbers" ON "phone_numbers"."id" = "callable_phone_numbers"."phone_number_id" WHERE "callable_phone_numbers"."callable_id" = ? AND "callable_phone_numbers"."callable_type" = ?  ORDER BY "phone_numbers"."last_received_message_at" DESC LIMIT 1  [["callable_id", 3], ["callable_type", "Student"]]
=> Thu, 06 Aug 2015 18:01:12 UTC +00:00
self.phone_numbers.sort_by { |pn| pn.last_received_message_at || Time.now - 20.year }.last.try(:last_received_message_at)