Ruby is somewhat versatile at times. Suppose you want to define a class dynamically, and I do….
class Thing; end
Ok, that’s not dynamic
# still not dynamic but getting there. def define_a_class Thing = Class.new end # ok then I see def define_a_class(name) Object.const_set(name, Class.new) end define_a_class('Thing') => Thing
This is great but what if you wanted to define a class within a module
define_a_class('Nigel::Thing') NameError: wrong constant name Nigel::Thing from (pry):19:in `const_set'
Oh. That sucks. What you’re actually trying to do here is
Object.const_set('Thing', Class.new) #=> Thing Nigel.const_set('Thing', Class.new) #=> Nigel::Thing
Object is for root namespace, and the module name for the nested namespace.
So today we had an issue. We normally define a Permit class if one doesn’t already exist like so.
def define_permit_class name = "#{self.name}Permit" Object.const_get(name) rescue NameError Object.const_set(name, Class.new(Permit)) end
This works for
Thing.define_permit_class
But obviously not for
Nigel::Thing.define_permit_class
Well, easily fixed. A class can find it’s parent module, or if it is doesn’t have one it’s Object.
Thing.parent #=> Object Nigel::Thing.parent #=> Nigel
So we just refactor this a little and bingo
def define_permit_class name = "#{self.name.demodulize}Permit" parent.const_get(name) rescue NameError parent.const_set(name, Class.new(Permit)) end
Ok, it now seems that parent is deprecated in Rails 6.1. module_parent it is.
DEPRECATION WARNING: `Module#parent` has been renamed to `module_parent`. `parent` is deprecated and will be removed in Rails 6.1.
Top comments (0)