[英]Rails query: get all parent records based on latest child records
An order has_many
order_events.订单
has_many
order_events。
An order_event
is a record of the state of the order, eg, pending_approval
, confirmed
, etc. order_event
是订单状态的记录,例如, pending_approval
, confirmed
等。
Changes to an order are tracked by creating order_events
.通过创建
order_events
来跟踪对订单的更改。
I usually get the current state of an order by doing something like: order.order_events.last.try(:state)
.我通常通过执行以下操作来获取订单的当前状态:
order.order_events.last.try(:state)
。
I would like a query to get all of the orders with a given current state, eg, all orders where the current state is cancelable
.我想要查询以获取具有给定当前状态的所有订单,例如,当前状态为
cancelable
所有订单。
I initially had a scope in the OrderEvent
model:我最初在
OrderEvent
模型中有一个范围:
scope :cancelable, -> { where('state = ? OR state = ?', 'pending_approval', 'pending_confirmation') }
and then a scope in the Order
model:然后是
Order
模型中的范围:
scope :with_dates_and_current_state_cancelable, -> { with_dates.joins(:order_events).merge(OrderEvent.cancelable) }
and simply used the latter for other purposes.并简单地将后者用于其他目的。
The problem here is that it returns all orders that are currently or have in the past satisfied the condition.这里的问题是它返回当前或过去满足条件的所有订单。
What is the best way to get all of the orders that currently satisfy the condition?获取当前满足条件的所有订单的最佳方法是什么?
I ended up using a query like this:我最终使用了这样的查询:
scope :with_dates_and_current_state_cancelable, -> {
with_dates
.joins(:order_events)
.where('order_events.created_at = (SELECT MAX(order_events.created_at) FROM order_events WHERE order_events.order_id = orders.id)')
.where('order_events.state = ? OR order_events.state = ?', 'pending_approval', 'pending_confirmation')
.group('orders.id')
}
A bit hard to read, but it seems to work.有点难以阅读,但它似乎有效。
A classic solution here would be to use Rails enum .这里的一个经典解决方案是使用 Rails enum 。
Add this to your order model:将此添加到您的订单模型中:
class Order
enum status: [ :pending_approval, :confirmed, etc.. ]
...
end
The status can be changed by doing the following:可以通过执行以下操作来更改状态:
# order.update! status: 0
order.pending_approval!
order.pending_approval? # => true
order.status # => "pending_approval"
No need for the order_events
model.不需要
order_events
模型。
To query all the orders that are pending approval:查询所有待审批的订单:
Order.where(status: :pending_approval)
Edit: Alternate solution when order_event
has necessary columns.编辑:当
order_event
有必要的列时的替代解决方案。
Add a column to the order_event
called archived
which can either be set to 1 or 0. Set the default scope in the order_event
model to this:向名为
archived
的order_event
添加一列,该列可以设置为 1 或 0。将order_event
模型中的默认范围设置为:
default_cope where(:archived => 0)
Assuming 0 is not archived.假设 0 未归档。
Now, when you create a new order event set the old event to 1.现在,当您创建新订单事件时,将旧事件设置为 1。
old_event = OrderEvent.find(params[:order_id])
old_event.update(archived: 1)
new_event = OrderEvent.create(...archived: 0)
Whenever you query for pending review like so:每当您像这样查询待审核时:
OrderEvent.where(:status => pending_approval)
Only events that are not archived will be shown.仅显示未存档的事件。
I think I figured out a query that might work.我想我想出了一个可能有效的查询。 I didn't turn it in to
ActiveRecord
methods, but here it is:我没有将它转换为
ActiveRecord
方法,但它是:
SELECT t.order_id
FROM
(SELECT MAX(created_at) AS created, order_id
FROM order_events
GROUP BY order_id) as t
INNER JOIN order_events
ON t.order_id = order_events.order_id AND
t.created = order_events.created_at
WHERE order_events.state = 'whatever_state_you_want'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.