1

我有 3 张属于同一货物的发票。创建的第一张发票始终是货件的主发票。

Invoice 
id   shipment_id
21   55 # This is the main invoice
88   55
93   55

如果我执行以下查询

s = Shipment.find(55)
s.invoices[0] # 21
s.invoices[1] # 88
s.invoices[2] # 93

所以我猜子元素的顺序是由他们的id决定的。我对吗?或者还有更多的东西吗?

我问是因为我需要确定子元素的顺序,以确保我的一种方法始终有效。

def am_i_the_main_invoice?
  if self.shipment.invoices[0].id == self.id
    true
  else
    false
  end
end
4

4 回答 4

2

除非您明确设置,否则顺序是随机的。虽然您的数据库现在可能会以相同的顺序返回元素,但如果您更改任何内容(即使是看似不相关的内容),它也可以是任何其他顺序。再说一遍:不要相信从关系数据库中检索到的元素的顺序,除非您在查询中明确设置了顺序。

在您Shipment可能已经设置has_many关系的班级中,您可以添加类似:order => "id ASC"始终按 id 强制执行顺序的内容。

于 2012-08-22T16:20:05.927 回答
1

您可以向表中添加一个标志,而不是依赖于有序查询invoices

# in migration
add_column :invoices, :is_primary, :boolean, {null: false, default: false}

# if your rdbms supports partial indexes, you can enforce it
execute 'create unique index uniq_single_primary on invoices (shipment_id) where is_primary = true'

# then query is easy ..
def am_i_the_main_invoice?
  self.is_primary?
end
于 2012-08-22T16:28:40.963 回答
1

返回的顺序通常取决于您使用的 SQL 数据库。通常它是基于主键的,但正如Holger所说,不要相信它,因为它可以改变。

您可以通过 2 种方式解决此问题:

  1. 在您的 Invoice 模型中添加一个范围,您可以在查看您的集合之前调用它,例如scope :by_shipment, order("id ASC")
  2. 添加一个 default_scope 以便始终按该顺序检索它,例如default_scope order("id ASC")

希望这可以帮助

于 2012-08-22T16:31:31.403 回答
1

为了可读性,我会添加一个关联扩展

class Shipment < ActiveRecord::Base
  has_many :invoices do
    def main
      @main_invoice ||=  first(:order => "id ASC")
    end

    def main?(id)
      main.try(:id) == id
    end
  end
end

现在您可以获得主发票,如下所示:

shipment.invoices.main # returns main invoice
shipment.invoices.main?(23) # checks if the invoice is a main invoice

这样,您就清楚地展示了main发票的概念。

于 2012-08-22T16:49:38.817 回答