Search code examples
ruby-on-rails

How to associate has_one relationships when using a generic id field?


I have an Activity model that will show a list of events that occurred (post created, event created, etc.).

In activity.rb, I have:

class Activity < ApplicationRecord
  has_one :post
  has_one :event
end

For my Activity migration file, I have it set up like so:

class CreateActivities < ActiveRecord::Migration[7.1]
  def change
    create_table :activities do |t|
      t.string :action, null: false
      t.string :action_model, null: false
      t.string :action_model_id, null: false

      t.timestamps
    end
  end
end

I'm using a generic action_model_id for reusability between different models (instead of needing to store a field for every association, for example: post_id, event_id, etc).

How can I call activity.post or activity.event while keeping this generic?


Solution

  • Models changes

    class Activity < ApplicationRecord
      belongs_to :action_model, polymorphic :true
    end
    
    
    class Post < ApplicationRecord
      has_many :activities, as: :action_model
    end
    
    
    class Event < ApplicationRecord
      has_many :activities, as: :action_model
    end
    

    And you need to change migration

    class CreateActivities < ActiveRecord::Migration[7.1]
      def change
        create_table :activities do |t|
          t.bigint :action_model_id, null: false
          t.string :action_model_type, null: false
    
          t.timestamps
        end
        add_index :activities, [:action_model_id, :action_model_type]
      end
    end