如何检查实例的所有记录是否具有值列表中的多个值之一?

时间:2018-07-16 16:35:42

标签: ruby-on-rails ruby aasm

我正在寻找复杂查询的解决方案。

目标:我想知道一个实例的所有记录是否都具有值,并在该实例的所有记录具有相同值时执行一些操作。

订单模型:

has_many :items
Columns : treated

项目模型:

belongs_to :order
Columns : order_id / state

种子示例:

Order.create
@item1 = Item.create(order_id: 1, state: pending)
@item2 = Item.create(order_id: 1, state: pending)

在回调操作中,在Item Model上,我已经完成:

def treatment
    self.order.items.each do |item|
      if item.state = "order_accepted" or item.state = "order_refused"
        item.order.update_attributes(treated: "true")
      end
    end
  end

所以我试图得到类似这样的结果:

“如果我所有的商品都具有“ order_accepted”或“ order_refused”状态,则将订单更新为“已处理”。”

请帮助! 非常感谢

1 个答案:

答案 0 :(得分:3)

您的问题标题与描述不符。您不是要检查“所有记录是否具有相同的值”,而是要检查所有记录是否具有多个值之一(来自列表)。

您的尝试存在一些问题:

self.order.items.each do |item|
  if item.state = "order_accepted" or item.state = "order_refused"
    # ...
  1. 冗余使用self
  2. 使用=设置值,而不是检查是否相等。 (可以通过==完成。)
  3. 通过像这样遍历所有items,您可以多次更新order
  4. ...而且由于您正在检查每个 item,而不是所有项,因此您无需检查它们是否是所有都具有所需的值。

您尝试成功的最小变化是:

if order.items.all? { |item| item.state == "order_accepted" || item.state == "order_refused" }
  order.update_attributes(treated: "true")
end

但是,这不是一个很好的解决方案,因为您要将所有对象都加载到内存中并遍历它们。这效率低下,尤其是在有许多items的情况下。更好的方法是直接在SQL 中而不是在ruby中执行检查

if order.items.where.not(state: ["order_accepted", "order_refused"]).empty?
  order.update_attribute(:treated, "true")
end

为了稍微整理一下这段代码,我将该查询定义为Item模型上的作用域,例如:

class Item < ApplicationRecord
  scope :not_completed, -> { where.not(state: ["order_accepted", "order_refused"]) }
end

然后也许也可以在Order模型上定义一个方法:

class Order < ApplicationRecord
  def complete?
    items.not_completed.empty?
  end
end

然后在上面的代码中,您只需编写:

def treatment
  # ...
  order.update_attribute(:treated, "true") if order.complete?
  # ...
end

此外,我怀疑应该确实是true而不是"true"true是布尔值; "true"是一个字符串。为作业使用正确的数据类型。

Rails可能会自动代表您将值转换为布尔值(?),但是无论如何,使用错误的数据类型都是我的不正确做法。