通过中介在同一模型上建立多对多关系 table
Many-to-many relationship on the same model via an intermediary table
我正在处理可以是购买或退款的交易,我需要将它们相互关联起来。一次购买可以多次退款(部分退款),一次退款可以连接多次购买。
我尝试按照描述建立关系here
这是我的交易模型:
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
当我调用 transaction.refunds 时,它失败并返回 NameError: uninitialized constant Transaction::RefundsPurchase"
,因此它试图在命名空间前加上当前的 class 前缀。如果我将关联模型移动到 Transaction::RefundsPurchase
命名空间,它会为 #Transaction:0x000055633d746440`
提供 NoMethodError: undefined method
refunds_purchases'
我做错了什么?
这里真正的问题实际上是您对域的其余部分建模的方式存在缺陷。您缺少包装一组购买的模型:
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
一个更典型的命名方案是订单项和订单。如果您想沿着使用单一 Table 继承而不是两个不同的 table 的路线走下去,您可以通过以下方式为退款和付款设置单独的关联:
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
我真的会考虑使用两个不同的 tables 进行退款和付款,如果您需要将其视为同质集合,则使用联合(或视图)。它将减少数据库与应用程序的关联,您希望获得比退款更多的付款,并且需要查询更多 table。
如果你想退款可以绑定到单次购买(特定订单项 order) 您可以添加一个单独的可为空的外键列:
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
这有一个重要的警告,即它排除了使用外键约束来保证参照完整性,这在涉及金钱时似乎是一个非常糟糕的主意。
我正在处理可以是购买或退款的交易,我需要将它们相互关联起来。一次购买可以多次退款(部分退款),一次退款可以连接多次购买。
我尝试按照描述建立关系here
这是我的交易模型:
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
当我调用 transaction.refunds 时,它失败并返回 NameError: uninitialized constant Transaction::RefundsPurchase"
,因此它试图在命名空间前加上当前的 class 前缀。如果我将关联模型移动到 Transaction::RefundsPurchase
命名空间,它会为 #Transaction:0x000055633d746440`
NoMethodError: undefined method
refunds_purchases'
我做错了什么?
这里真正的问题实际上是您对域的其余部分建模的方式存在缺陷。您缺少包装一组购买的模型:
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
一个更典型的命名方案是订单项和订单。如果您想沿着使用单一 Table 继承而不是两个不同的 table 的路线走下去,您可以通过以下方式为退款和付款设置单独的关联:
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
我真的会考虑使用两个不同的 tables 进行退款和付款,如果您需要将其视为同质集合,则使用联合(或视图)。它将减少数据库与应用程序的关联,您希望获得比退款更多的付款,并且需要查询更多 table。
如果你想退款可以绑定到单次购买(特定订单项 order) 您可以添加一个单独的可为空的外键列:
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
这有一个重要的警告,即它排除了使用外键约束来保证参照完整性,这在涉及金钱时似乎是一个非常糟糕的主意。