在Rails中建模`has_two`关系的最佳方法是什么?

时间:2015-12-17 09:17:06

标签: ruby-on-rails activerecord foreign-keys

我有一个Contract模型,每个模型有两个Paymentprepaymentsecond_payment)。

我知道一种可行的方法可能如下:

class Contract < ActiveRecord::Base
  belongs_to :prepayment, :class_name => "Payment"
  belongs_to :second_payment, :class_name => "Payment"
end


## Schema 
create_table "contracts" do |t|
  t.integer  "prepayment_id"
  t.integer  "second_payment_id"
end

但从逻辑上讲,对于属于contract的{​​{1}}或者payment有合同,这听起来不合适。应该反过来。

建立这种关系的最佳做法是什么?

3 个答案:

答案 0 :(得分:1)

我宁愿使用支付模式关联正常,也可以在支付中添加一个类别,“预付款”可以是0,“付款”可以是1。通过这种方式,您可以通过添加其他类别来进行其他类型的付款,并且您不需要每次都修改关联。

class Contract < ActiveRecord::Base
  has_many :payments
end

class Payment < ActiveRecord::Base
  enum category: [ :payment, :prepayment ]
end

## Schema 
create_table "prepayment" do |t|
  t.integer  "category"
end

答案 1 :(得分:0)

逻辑方法是使用这个(简单实现):

class Contract < ActiveRecord::Base
  has_many :payment_transactions, as: :transactionable
end

class PaymentTransaction < ActiveRecord::Base
  belongs_to :transactionable, polymorphic: true
end

对于PaymentTransaction,您可以使用枚举字段:

enum payment_type: [:first_income, :expense]

答案 2 :(得分:0)

我这样做:

#app/models/contract.rb
class Contract < ActiveRecord::Base
   has_many :payments, -> { where(category: [0,1]) } #-> only returns the payments where category is "prepayment" or "secondary_payment"
end

#app/models/payment.rb
class Payment < ActiveRecord::Base
   belongs_to :contract
   enum category: [:prepayment, :secondary_payment]

   validates :category, uniqueness: { scope: :contract_id } #-> only one of each category per contract

   scope :pre,       -> { find_by category: 0 }
   scope :secondary, -> { find_by category: 1 }
end

这样,您就可以使用以下内容:

@contract = Contract.find(1)

@contract.payments.pre
@contract.payments.secondary