Reputation: 1570
I have a Contract
model, each of which has two Payment
(prepayment
and second_payment
).
I know one possible way to do so may be as follow:
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
But in a logical sense, it really doesn't sound right for a contract
belonging to a payment
, or a payment
has a contract. Should be the other way round.
What is the best practice to model this kind of relationship?
Upvotes: 1
Views: 164
Reputation: 470
I would rather use Payment model association normal as it would be and than add a category to Payment that can be 0 for "prepayment" and 1 for "payment". In that way in the future you could also have other type of payments just by adding another category and you don't need to modify the association every time.
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
Upvotes: 1
Reputation: 76774
I'd do this:
#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
This way, you'll be able to use the following:
@contract = Contract.find(1)
@contract.payments.pre
@contract.payments.secondary
Upvotes: 0
Reputation: 3869
A logic way would be to use this (simple realization):
class Contract < ActiveRecord::Base
has_many :payment_transactions, as: :transactionable
end
class PaymentTransaction < ActiveRecord::Base
belongs_to :transactionable, polymorphic: true
end
For PaymentTransaction you can use enum field:
enum payment_type: [:first_income, :expense]
Upvotes: 0