如何通过Ruby on Rails中从相同基类继承的多个子类的属性进行排序?

时间:2010-01-19 19:26:37

标签: ruby-on-rails activerecord sorting

我有4个班 - 病人,医生,人和预约。 Patient和Doctor是Person的子类。任命属于患者,属于医生。

我想写一个AR语句来按病人的姓氏和另一个来排序约会,按医生的姓氏排序,因为所有约会都在可排序的表格中。我对AR查找语句的“顺序”选项中的内容感到困惑。如果我把

:order => 'patient.last_name'

我收到mysql错误 - “未知列'patient.last_name' 这是有道理的,因为没有患者专栏,这是一个patient_id指的是外国“人”对象。当然我可以按person.last_name排序,但我不知道如何指定排序的人 - 医生或病人。

我还应该注意,我正在使用include选项来急切地加载患者和医生。

更新

只有人员表和约会表。病人和医生都是从这个人那里继承的。 patients.last_name不起作用,因为没有患者表。

AR声明是:

find  :all,
                :include => [:doctor, :patient], 
                :order => 'something needs to go here'   

“需要去的地方”应该是医生的姓氏或患者姓氏的命令。

2 个答案:

答案 0 :(得分:1)

你可以这样做:

Appointment.find(:all, :include => {:patient}, :order => 'people.last_name')

您正在做的是同时抓住所有约会及其相关患者。您不必担心患者与医生,因为检索到的所有行都将是患者记录。

为了获得以医生为中心的清单,只需更改:患者为:上述例子中的医生。

编辑:当你急切地加载患者和医生时,我想出了解决方案。它有点复杂。首先,我在空白的rails应用程序中重新创建了4个模型的简单版本,然后尝试使用:order => 'patients.name'运行查找:

Appointment.find(:all, :include => [:patient, :doctor], :order => 'patients.name')

当然如果失败了,但它也吐出了它试图的SQL查询:

SELECT
  "appointments"."id" AS t0_r0, 
  "appointments"."name" AS t0_r1, 
  "appointments"."doctor_id" AS t0_r2, 
  "appointments"."patient_id" AS t0_r3, 
  "appointments"."created_at" AS t0_r4, 
  "appointments"."updated_at" AS t0_r5, 

  "people"."id" AS t1_r0, 
  "people"."name" AS t1_r1, 
  "people"."type" AS t1_r2, 
  "people"."created_at" AS t1_r3, 
  "people"."updated_at" AS t1_r4, 

  "doctors_appointments"."id" AS t2_r0, 
  "doctors_appointments"."name" AS t2_r1,
  "doctors_appointments"."type" AS t2_r2, 
  "doctors_appointments"."created_at" AS t2_r3, 
  "doctors_appointments"."updated_at" AS t2_r4
FROM "appointments"
LEFT OUTER JOIN "people" ON "people".id = "appointments".patient_id AND  ("people"."type" = 'Patient' )  
LEFT OUTER JOIN "people" doctors_appointments ON "doctors_appointments".id = "appointments".doctor_id AND  ("doctors_appointments"."type" = 'Doctor' )  
ORDER BY patients.name

现在我们可以看到rails如何构成这样的查询。使用给定表的第一个关联直接获取表名 - “people”。后续关联获得了关联和原始表的组合 - “doctors_appointments”。

看起来有点乱,但是这个电话让你按照病人命令:

Appointment.find(:all, :include => [:patient, :doctor], :order => 'people.name')

这个给你医生订购:

Appointment.find(:all, :include => [:patient, :doctor], :order => 'doctors_appointments.name')

当然,在我的例子中,我只为每个人提供了一个简单的名称字段,而您将使用“last_name”代替。但是你明白了。这对你有用吗?

最后一次编辑:

我会把它们放在查找器中,所以你不需要在代码中的任何其他地方弄乱表名。我会这样做:

class << self
  def order_by_patient(field='last_name')
    find(:all, :include => [:patient, :doctor], :order => "people.#{field}")
  end

  def order_by_doctor(field='last_name')
    find(:all, :include => [:patient, :doctor], :order => "doctors_appointments.#{field}")
  end
end

现在你可以从任何地方打电话给他们,甚至按你想要的字段排序。

答案 1 :(得分:0)

我认为你可能需要使用手动连接而不是包含。

请参阅Active Record Querying Guide on Joining Tables

然后,您可以为表名创建别名,并相应地对它们进行排序。

find.all(:joins => 'LEFT OUTER JOIN people dr ON dr.id = appointments.id'
  :order => dr.last_name
)

或类似的数据库。

或者,您可以添加包含整数的“排序”列。所有医生都有1,患者有0。然后您可以ORDER BY last_name,sort_column,结果将根据医生/患者排序值相应地排列在last_name组内。

注意:我今天早上还没有喝咖啡,所以加入可能都是不合时宜的,但你会得到我希望的一般想法。