Search code examples
ruby-on-railsrubyreflectionassociations

Is there a way dynamically set class_name in belong_to associations


I have this class Churned

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

now, I have another subscription table called SubscriptionA.

what I am trying to achieve is

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

I want to be able to pass two different class instances (NewSubscription or SubscriptionA) to :subscription when I am creating activity. I do not want to change currect database schema, so polymorphic assosciation as :subscriptable something that I do not want to do.

I tried something like this but that does not work

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

Solution

  • I know there is already a comment saying the polymorphic association is your choice. But let there be an answer.

    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
    

    In your migration you have to use

    t.references :subscription, polymorphic: true
    

    Or manually add 2 fields: subscription_id and subscription_type and indexes.

    You won't be able to rely on foreign key constrains if using any, that's beyond standard behavior of many DB's (Postgres, e.g.), but that should not be a big deal.