How make a concern parameterized?

The following 2 options work. I’m wondering which is preferable. I’m trying to have a validation concern be “parameterized”.

A Concern That Uses a Class Method

This is the concern that needs to be “parameterized”:

module Addressable
  extend ActiveSupport::Concern

  included do
    zip_field = "#{address_prefix}_zip_code".to_sym
   
    zip_code_regexp = /^\d{5}(?:[-\s]\d{4})?$/
    
    validates zip_field, format: zip_code_regexp, allow_blank: true
end

I found 2 ways to set the address_prefix before including the Addressable concern.

When the concern module is included in the class

The class method needs to be defined before including the concern

cattr_accessor :address_prefix
self.address_prefix = "home"
include Addressable

or like this

def self.address_prefix
    "home"
end
include Addressable

When the concern module is included in another module

The trick here is to override self.append_features and to add the method.

  def self.append_features(base)
    base.class_eval do
      def self.address_prefix
        "home"
      end
    end
    super
  end

or

  def self.append_features(base)
    base.cattr_accessor :address_prefix
    base.address_prefix = "home"
    super
  end

Questions

  1. What preferable, the cattr_accessor way or defining the class method?
  2. For the concern within a concern situation, is overriding self.append_features the correct hook?
  3. Is class_eval the right call to create the method, rather than class exec? Or really doesn’t matter if the code doesn’t need access to instance variables. Module docs here.
  4. How could I include this concern twice, say for a prefix of “work” and a prefix of “home” so the validations would apply to both. Clearly setting the class method on the including class would not work. Or maybe it would if the method is redefined between inclusions? Any cleaner way?

I think if this were a requirement, then the attribute_prefix could optionally return an array.

My preferred way of defining class level accessors is with:

class << self
  attr_accessor :name
end

I think the overall approach of trying to pass [class] parameters to a module is bad design. Your 4th question points out a fatal flaw: it can’t be used for multiple *_zip_code fields. And class methods that rely on class attributes seem brittle, especially for mixins (like it is here).

The only time I’ve needed something like this is with gem configuration. Maybe this is just a bad example? I mean, there are more conventional ways of achieving the same result here.