通过中间表在同一模型上建立多对多关系



我正在处理可以是购买或退款的交易,我需要将它们彼此连接起来。一次购买可以有多次退款(部分退款),一次退款可以连接到几次购买。

我试着建立这里描述的关系

这是我的事务模型:

class Transaction < ApplicationRecord
has_many :refunds_purchases, foreign_key: :transaction_id, class_name: 'RefundsPurchase'
has_many :refunds, through: :purchases_refunds, source: :refund
has_many :purchases_refunds, foreign_key: :transaction_id, class_name: 'RefundsPurchase'
has_many :purchases, through: :refunds_purchases, source: :purchase
end

下面是关联模型:

class RefundsPurchase < ApplicationRecord
belongs_to :purchase, foreign_key: :purchase_id, class_name: 'Transaction'
belongs_to :refund, foreign_key: :refund_id, class_name: 'Transaction'
end

当我调用事务时。退款它与NameError: uninitialized constant Transaction::RefundsPurchase"失败,所以它试图用当前类前缀前缀命名空间。如果我将关联模型移动到Transaction::RefundsPurchase命名空间,它会给NoMethodError: undefined method退款s_purchase ' for #Transaction:0x000055633d746440 '

我做错了什么?

这里真正的问题实际上是您如何对域的其余部分建模的不足。您缺少一个包装一组购买的模型:

class Purchase < ApplicationRecord
belongs_to :purchase_order
has_many :transactions, through: :purchase_orders
end
class PurchaseOrder < ApplicationRecord
has_many :purchases
has_many :transactions
end 
class Transaction < ApplicationRecord
belongs_to :purchase_order
has_many :purchases, through: :purchase_order
end
更典型的命名方案是行项命令。如果您想使用单表继承而不是两个不同的表,您可以通过以下方式为退款和付款设置单独的关联:
class Purchase < ApplicationRecord
belongs_to :purchase_order
has_many :transactions, through: :purchase_orders
end
class PurchaseOrder < ApplicationRecord
has_many :purchases
has_many :transactions
has_many :payments
has_many :refunds
end 
# make sure to add varchar column named 'type' to the table 
class Transaction < ApplicationRecord
belongs_to :purchase_order
has_many :purchases, through: :purchase_order
end
class Payment < Transaction
end
class Refund < Transaction
end

我真的会考虑使用两个不同的表进行退款和付款,如果需要将其视为同质集合,则使用联合(或视图)。它将使数据库与应用程序的联系更少,并且您可能会有更多的付款和退款,并且需要更多地查询该表。

如果您想使退款可以绑定到单个购买(订单上的特定行项),您可以添加一个单独的可空外键列:

class Transaction < ApplicationRecord
belongs_to :purchase_order, optional: true
belongs_to :purchase, optional: true
has_many :purchases, through: :purchase_order
def item
purchase_order || purchase
end
end

或者使用多态关联:

class Transaction < ApplicationRecord
belongs_to :item, polymorphic: true
has_many :purchases, through: :purchase_order
end

这有一个很大的警告,它排除了使用外键约束来保证引用完整性,当涉及到金钱时,这似乎是一个非常糟糕的主意。

最新更新