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
- What preferable, the
cattr_accessor
way or defining the class method? - For the concern within a concern situation, is overriding
self.append_features
the correct hook? - Is
class_eval
the right call to create the method, rather thanclass exec
? Or really doesn’t matter if the code doesn’t need access to instance variables. Module docs here. - 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?