开发者

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

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开发者_如何学C 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


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.


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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜