Accessing included class's protected constant in a ActiveSupport::Concern
Asked Answered
S

2

6

What's the simplest way to access included class's protected constant in the ActiveSupport::Concern context?

Example classes:

module Printable
    extend ActiveSupport::Concern

private
    def print_constant
        puts MY_CONSTANT
    end
end

class Printer
    include Printable

    def print
        print_constant
    end

private
    MY_CONSTANT = 'Hello'.freeze
end

This solution produces an error:

NameError: uninitialized constant Printable::MY_CONSTANT

I'm aware of an alternative that seems to work:

puts self.class::MY_CONSTANT

But, it doesn't feel right. :-)

Any better suggestions?

Sham answered 30/9, 2014 at 12:24 Comment(1)
Your question was my answer. While I agree that it doesn't feel right, your question finally gave me a solution that at least worked.Kalinin
V
9

First of all, you should put #print_constant into an included block:

module Printable
  extend ActiveSupport::Concern

  included do
    private

    def print_constant
      puts MY_CONSTANT
    end
  end
end

Now there are at least two ways of accessing the class constant MY_CONSTANT:

  1. #included yields with a base parameter similar to Ruby's #included:

    module Printable
      extend ActiveSupport::Concern
    
      included do |base|
        private
    
        define_method :print_constant do
          puts base::MY_CONSTANT
        end
      end
    end
    
  2. Another method is going from self.class:

    module Printable
      extend ActiveSupport::Concern
    
      included do
        private
    
        def print_constant
          puts self.class::MY_CONSTANT
        end
      end
    end
    

ActiveSupport Concern Documentation

Verner answered 31/12, 2015 at 1:48 Comment(0)
H
1

Accessing a constant of an including class from a concern isn't really a good idea.

A concern shouldn't have (too much) knowledge of the classes it's included in.

I would go for a common API in the concern and override when needed... like this:

module Printable
    extend ActiveSupport::Concern

private
    def print
      puts ""
    end
end

class Printer
    include Printable

    def print
        MY_CONSTANT
    end

private
    MY_CONSTANT = 'Hello'.freeze
end
Hoi answered 15/4, 2015 at 15:9 Comment(1)
You'll have a method hyperinflation on the order of (number of including classes) x (number of methods using the constant) :)Donelson

© 2022 - 2024 — McMap. All rights reserved.