Given the following model and concerns

def MyModel
   include ConcernA
   include ConcernB
end

module ConcernA
  extend ActiveSupport::Concern
  def print_a
    formatted_text
  end
protected
  def formatted_text
    "ConcernA"
  end
end

module ConcernB
  extend ActiveSupport::Concern
  def print_b
    formatted_text
  end
protected
  def formatted_text
    "ConcernB"
  end
end

The formatted_text method gets overwritten

=> MyModel.print_a
= "ConcernB"

=> MyModel.print_b
= "ConcernB"

Is there a way to actually protect the formatted_text method so that it is only accessible within the concern and therefore not overwritten?

1 Answers

1
Sergio Tulentsev On Best Solutions

There's no hard protection. If someone wants to change something, they most likely will be able to. But you can devise some safeguards against accidental name clash.

For example, extract the method into its own namespace:

module ConcernA
  extend ActiveSupport::Concern
  def print_a
    Impl.new.formatted_text
  end

  class Impl
    def formatted_text
      "ConcernA"
    end
  end
end

module ConcernB
  extend ActiveSupport::Concern
  def print_b
    Impl.new.formatted_text
  end

  class Impl
    def formatted_text
      "ConcernB"
    end
  end
end

class MyModel
   include ConcernA
   include ConcernB
end


MyModel.new.print_a # => "ConcernA"
MyModel.new.print_b # => "ConcernB"

This way, ConcernA::Impl and ConcernB::Impl are two unrelated classes and don't affect each other.