Rails:没有通过表的自引用父/子层次结构

Jac*_*ham 5 activerecord ruby-on-rails

我有一个带有parent_iddate属性的事件模型:

Event.rb

has_many :children, :class_name => "Event"
belongs_to :parent, :class_name => "Event" 
Run Code Online (Sandbox Code Playgroud)

我没有问题event.parentevent.children.儿童事件本身从未有过孩子.

我正在尝试为此模型添加一个范围,以便我可以为每个父项返回最近的日期.就像是:

scope :future, -> {
    where("date > ?", Date.today)
  }

scope :closest, -> {
    group('"parent_id"').having('date = MAX(date)')
 }

Event.future.closest ==> returns the closest child event from every parent
Run Code Online (Sandbox Code Playgroud)

但上述:closest范围是每个父母返回一个以上的孩子.

Pau*_*rth 1

暂时忽略 Rails,您在 SQL 中所做的事情是问题。这里有很多解决方案。我会选择DISTINCT ONLEFT OUTER JOIN LATERAL。它在 Rails 中的外观如下:

scope :closest, -> {
  select("DISTINCT ON (parent_id) events.*").
    order("parent_id, date ASC")
}
Run Code Online (Sandbox Code Playgroud)

这将为您提供子对象。(您可能还需要一个条件来排除没有 的行parent_id。)从您自己的解决方案来看,听起来这就是您想要的。相反,如果您想要父对象以及可选的附加子对象,则使用横向连接。不过,将其转换为 ActiveRecord 有点棘手。如果可以接受在两个查询中执行此操作,那么看起来它应该可以工作(坚持使用DISTINCT ON):

has_one :closest_child, -> {
  select("DISTINCT ON (parent_id) events.*").
    order("parent_id, date ASC")
}, class_name: Event, foreign_key: "parent_id"
Run Code Online (Sandbox Code Playgroud)

那么你可以说Event.includes(:closest_child)。同样,您可能想过滤掉所有非父母。