How do I sort a parent class based on an attribute of the child class?

隐身守侯 提交于 2020-01-05 04:51:26

问题


I have what seemed to me a simple requirement: I want to sort a parent class based on an attribute of its child class.

class owner
  has_many :tasks
end

class task
  belongs_to :owner
end

Now I want to sort the owners based on the due date on their tasks, so that the owner that has the task with the "closest" due date is first, etc

I can do this in Ruby with array sorting, but my record sets are huge and i need to do this with AR / DBMS..

UPDATE:
As I am pondering this question part of the solution occurred to me, although I don't know how to implement in AR.

To sort the owners based on their tasks, only a single task (per owner) is relevant, namely the one with the closest due date.

How would I use AR to fetch me all the owners, sorted by their task with the closest due date?

UPDATE 2:

Task.order("due_date DESC").maximum("due_date", :group => 'owner')

Will actually give me the owner objects, sorted in the right order as part of an ordered hash ( [owner] => "due_date"). Hooray! The only problem now is, how do I tell AR to eager_load all the associated tasks with the owner object. Because at this moment its firing a query everytime i call

owner.tasks.each do |t|

in my view.

Any help appreciated, i'm going nuts with this (simple??) problem,
Erwin


回答1:


Ok, so in the end I figured it out myself.

Owner.includes(:tasks).joins(:tasks).order("tasks.due_date").group(:id)

will sort the Owners based on the closest due date in their tasks and will eager load all tasks, resulting in a single query.

Update: added the generated SQL in response to Mladen's comment below.

SELECT `owners`.* FROM `owners` 
INNER JOIN `tasks` ON `tasks`.`owner_id` = `owner`.`id` 
GROUP BY owner.id ORDER BY tasks.due_date DESC

Cheers.




回答2:


Found this possible only by pure query:

Owner.find_by_sql('SELECT `owners`.*,
                           (SELECT `tasks`.`due_date`
                            FROM `tasks`
                            WHERE `owners`.`id` = `tasks`.`owner_id`
                            ORDER BY `tasks`.`due_date` DESC LIMIT 1) AS `last_due_date`
                   FROM `owners`
                   GROUP BY `owners`.`id`
                   ORDER BY `last_due_date` DESC;')

If need access to last_due_date then add to Owner model:

def last_due_date
  if attributes['last_due_date']
    attributes['last_due_date']
  else
    tasks.order(due_date: :desc).limit(1).first.due_date if tasks.length > 0
  end
end


来源:https://stackoverflow.com/questions/5544416/how-do-i-sort-a-parent-class-based-on-an-attribute-of-the-child-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!