如何在belongs_to关联中确定第一个子元素?

时间:2012-08-22 16:14:01

标签: ruby-on-rails ruby

我有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 个答案:

答案 0 :(得分:2)

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

在您可能已设置Shipment关系的has_many课程中,您可以添加:order => "id ASC"之类的内容,以便始终按ID强制执行订单。

答案 1 :(得分: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

答案 2 :(得分:1)

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

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

  1. 在您的发票模型中添加范围,您可以在查看集合之前调用该范围,例如: scope :by_shipment, order("id ASC")
  2. 添加default_scope,以便始终按该顺序检索它,例如default_scope order("id ASC")
  3. 希望这有帮助

答案 3 :(得分: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发票的概念。

相关问题