如何添加关系,使相关对象出现在ActiveRecord CollectionProxy中的某个位置?

How to add a relationship so that related object would appear in a certain position in ActiveRecord CollectionProxy?

情况:

我有 4 个模型具有如下关系:

class A < ActiveRecord::Base
  belongs_to :b
  belongs_to :c
  belongs_to :d
end

class B < ActiveRecord::Base
  has_many :as, dependent: :destroy
end

class C < ActiveRecord::Base
  belongs_to :d
end

class D < ActiveRecord::Base
  has_many :cs, dependent: :destroy
end

问题:

我需要将模型 A 对象 a 与模型 B 对象相关联 b 但我还需要为对象 a 设置一个位置 ActiveRecord CollectionProxy调用 b.as 时不起作用。 所有将对象 a 添加到 a.bs 中特定位置的尝试最终都会在末尾 新添加 a。有可能吗?我知道有可能在数组中和查询时定义排序,但是在添加新关系时是否可以直接定义排序?

示例:

模型 B 对象 b 有 3 个模型 A 对象。

b.as
  => #<ActiveRecord::Associations::CollectionProxy [
    #<A id: 39038, quantity: 3.0 created_at: "2016-02-01 15:51:26", updated_at: "2016-02-01 15:51:26", d_id: 4144, c_id: nil, b_id: 81218>, 
    #<A id: 39039, quantity: 2.0, created_at: "2016-02-01 15:51:26", updated_at: "2016-02-01 15:51:26", d_id: 4145, c_id: nil, b_id: 81218>,
    #<A id: 39040, quantity: 2.0, created_at: "2016-02-01 15:51:26", updated_at: "2016-02-01 15:51:26", d_id: 4145, c_id: 1590, b_id: 81218>]>

我创建了第四个模型 A 对象 a,我需要它在调用 b.as 时出现在第二位,如下所示:

a = A.create(quantity: 4.0, d: D.find(4144), c: C.find(1612), b: b)

基本上顺序应该这样定义:

b.as
=>
  a1: d_id: 4144, c_id: nil
  a2: d_id: 4144, c_id: 1612
  a3: d_id: 4145, c_id: nil
  a4: d_id: 4145, c_id: 1590

...意味着每个具有相同 d_id 属性的 a 对象应该被组合在一起,同时将具有 c_id.nil? 的那些 a 放在首位。

add 方法总是将它添加到列表的末尾。您需要某种位置属性来实现您想要的。如果你不想自己实现,你可以看看 Acts as list gem。另一种选择是在 As 模型上添加 default_scope { order: :key_to_order_by }

has_many :as, -> { order(d_id: :asc, c_id: :asc) }

应该很接近,除了 nil 排在最高 cd_id 之后。那是 postgres 做的排序,所以我不知道你是否可以在那里做很多事情。