Code Quality Catch-22 -- Duplication vs Complexity
Your first version - extending the association - is probably the right approach in general, but there's another way to remove duplication, without resorting to metaprogramming.

Instead of defining methods as inlined extensions you can create a module for the association extensions. But rather than adding that module to the User model, you can add it the associations instead (see the docs)

E.g. if you create a module like so:

module TrackableAssociation
  def &lt;&lt;(item)
    # ...
  end

  def activate(item)
    # ...
  end

  def deactivate(item)
    # ...
  end
end


You should be able to add it like so:

class User &lt; ActiveRecord::Base
  has_many :conditions, through: :user_conditions, -&gt; { extending TrackableAssociation }
  has_many :symptoms, through: :user_symptoms, -&gt; { extending TrackableAssociation }
  has_many :treatments, through: :user_treatments, -&gt; { extending TrackableAssociation }
end


Which, in turn, should let you do things like

user.conditions.activate(condition)


Now your extensions are defined without using duplication or metaprogramming.

However. Your approach of storing an array of "activated IDs" smells fishy. It's fragile, and it requires the association extensions to modify the user instance. The code paths get tricky.

active should be an attribute on a join model - or at least a column in the join table. If I'm reading your code right, you've got Condition, Symptom and Treatment models, and join tables between them and User. You should probably make actual models for the join; said models can then have an active boolean attribute.