Techioz Blog

begin_to 関連付けで class_name を動的に設定する方法はありますか

概要

このクラスをチャーンしました

module AccountActivities
  class Churned < AccountActivity
    belongs_to :subscription, class_name: 'NewSubscription'
  end
end

現在、SubscriptionS という別のサブスクリプション テーブルがあります。

私が達成しようとしているのは

@subscription_activity = AccountActivities::Chunrned.create!(
          subscription: subscription(in this case this could be NewSubscription or SubscriptionA class instance),
        )

アクティビティを作成するときに、2 つの異なるクラス インスタンス (NewSubscription または SubscriptionA) を :subscription に渡せるようにしたいと考えています。現在のデータベーススキーマを変更したくないので、:subscriptable としてのポリモーフィックな関連付けはやりたくないものです。

このようなことを試しましたが、うまくいきません

class Churned < AccountActivity

  belongs_to :plan
  belongs_to :subscription, class_name: :determine_subscription_class


  private

  def determine_subscription_class
    if some_condition about :plan
      'NewSubscription'
    else
      'SubscriptionA'
    end
  end
end

解決策

ポリモーフィックな関連付けはあなたの選択であるというコメントがすでにあることは承知しています。しかし、答えを出してみましょう。

class Churned < ApplicationRecord
  belongs_to :subscription, polymorphic: true
end

class SubscriptionOne < ApplicationRecord
  has_many :churned, as: :subscription
end

class SubscriptionTwo < ApplicationRecord
  has_many :churned, as: :subscription
end

移行では使用する必要があります

t.references :subscription, polymorphic: true

または、subscription_id、subscription_type、インデックスの 2 つのフィールドを手動で追加します。

外部キー制約を使用する場合、外部キー制約に依存することはできません。これは多くの DB (Postgres など) の標準動作を超えていますが、それは大きな問題ではありません。