【问题标题】:How do I sort a parent class based on an attribute of the child class?如何根据子类的属性对父类进行排序?
【发布时间】:2011-04-04 21:12:38
【问题描述】:

我有一个对我来说似乎很简单的要求:我想根据子类的属性对父类进行排序。

class owner
  has_many :tasks
end

class task
  belongs_to :owner
end

现在我想根据任务的截止日期对所有者进行排序,以便拥有“最接近”截止日期的任务的所有者排在第一位,等等

我可以在 Ruby 中通过数组排序来做到这一点,但我的记录集很大,我需要用 AR / DBMS 来做到这一点..

更新:
当我在思考这个问题时,我想到了部分解决方案,尽管我不知道如何在 AR 中实现。

要根据所有者的任务对所有者进行排序,只有一个任务(每个所有者)是相关的,即截止日期最近的任务。

我将如何使用 AR 为我获取所有所有者,按他们的任务和最接近的截止日期排序?

更新 2:

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

实际上会给我所有者对象,作为有序哈希的一部分([所有者] =>“due_date”)以正确的顺序排序。万岁!现在唯一的问题是,我如何告诉 AR 使用所有者对象进行 eager_load 所有相关任务。因为此时每次我调用它都会触发一个查询

owner.tasks.each do |t|

在我看来。

任何帮助表示赞赏,我对这个(简单的??)问题很感兴趣,
欧文

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 activerecord


    【解决方案1】:

    好的,所以最后我自己想通了。

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

    将根据任务中最接近的到期日期对所有者进行排序,并将预先加载所有任务,从而产生一个查询。

    更新:添加生成的 SQL 以响应 Mladen 下面的评论。

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

    干杯。

    【讨论】:

    • 你能把生成的SQL粘贴到这里吗?谢谢。
    • 谢谢。但是我认为该查询在 Postgres 中不起作用。
    【解决方案2】:

    仅通过纯查询发现这可能:

    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;')
    

    如果需要访问last_due_date,则添加到Owner 模型:

    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
    

    【讨论】:

    • 我建议对last_due_date 方法进行一项更改。问题是,如果该属性由数据库返回并设置为nil,Rails 将继续尝试再次评估它。当您知道它不应该存在时,您会在日志中看到一堆数据库访问,并且问题很难调试。我会将第一行更改为if attributes.has_key?('last_due_date')
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-17
    • 1970-01-01
    • 2016-03-02
    • 2019-06-30
    • 2015-02-02
    • 1970-01-01
    • 2020-05-15
    相关资源
    最近更新 更多