用抽象类在Rails中表示has_many关系

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用抽象类在Rails中表示has_many关系相关的知识,希望对你有一定的参考价值。

我有一段关系,我很难建模。

我有一个Subscription类,它是一个常规的ActiveRecord模型,它可以有一个或多个PaymentSources。然而问题是支付来源可能指的是CreditCardBankAccount

鉴于这些模型具有与之相关的非常不同的数据,我觉得STI在这里不是一个好选择。所以我想知道是否存在针对Rails中的情况的已建立或推荐的方法,其中模型具有另一个模型的实例,其实际上是2个或更多个不共享相同数据布局的类的抽象。

理想情况下,在这个特殊的例子中,我可以说像subscription.payment_source.default这样的东西,并且根据用户选择的首选计费方法,它指的是CreditCardBankAccount

答案

TLDR:

[更新]经过一番思考后,我会做选项2(更完整的解决方案),这是一个面向未来的灵活方案,但如果你不需要所有这些复杂性,我只会做选项1。

选项1:

class Subscription < ApplicationRecord
  belongs_to :credit_card
  belongs_to :bank_account

  def payment_sources
    [credit_card, bank_account].compact
  end

  def default_payment_source
    case user.preferred_billing_method # assuming you have an integer column in users table called `preferred_billing_method`
    when 0 then credit_card # asssuming 0 means "Credit Card"
    when 1 then bank_account # assuming 1 means "Bank Account"
    else NotImplementedError
    end
  end
end

Usage

Subscription.first.default_payment_source
# => returns either `CreditCard` or `BankAccount`, or `nil`

Subscription.first.payment_sources.first
# => returns either `CreditCard` or `BankAccount`, or `nil`

选项2:

class User < ApplicationRecord
  belongs_to :default_payment_source, class_name: 'PaymentSource'
  has_many :subscriptions
end

class Subscription < ApplicationRecord
  belongs_to :user
  has_many :payment_sources_subscriptions
  has_many :payment_sources, through: :payment_sources_subscriptions
end

# This is just a join-model
class PaymentSourcesSubscription < ApplicationRecord
  belongs_to :subscription
  belongs_to :payment_source

  validates :subscription, uniqueness: { scope: :payment_source }
end

# this is your "abstract" model for "payment sources"
class PaymentSource < ApplicationRecord
  belongs_to :payment_sourceable, polymorphic: true
  has_many :payment_sources_subscriptions
  has_many :subscriptions, through: :payment_sources_subscriptions

  validates :payment_sourceable, uniqueness: true
end

class CreditCard < ApplicationRecord
  has_one :payment_source, as: :payment_sourceable
end

class BankAccount < ApplicationRecord
  has_one :payment_source, as: :payment_sourceable
end

Usage:

User.first.default_payment_source.payment_sourceable
# => returns either `CreditCard` or `BankAccount`, or `nil`

Subscription.first.payment_sources.first.payment_sourceable
# => returns either `CreditCard` or `BankAccount`, or `nil`

以上是关于用抽象类在Rails中表示has_many关系的主要内容,如果未能解决你的问题,请参考以下文章

在has_many中过滤子对象:通过Rails 3中的关系

Rails RSpec 测试 has_many :through 关系

Rails 4:加入 has_many 关系

Rails 视图:加入 has_many 关系而不是遍历它们?

何时在 Rails 中使用“has_many :through”关系?

Rails 4找不到关联has_many,通过:关系错误