I want to be able to include my module in ActiveRecord::Base so that the has_folder_attachments
method is available to my Rails AR classes.
I'm doing this to extend the original module's function to support AR hooks; however the variables @physical_path
and @dice
are both nil and I don't understand why.
module FolderAttachments
module ClassMethods
def has_folder_attachments(physical_path, excludes: [])
@physical_path = physical_path
super
end
end
def self.prepended(base)
class << base
prepend ClassMethods
end
end
attr_reader :physical_path
end
module ActiveRecord
class Base
prepend FolderAttachments
attr_reader :dice
# This should run after the module method
def self.has_folder_attachments(*args)
@dice = true
end
end
end
class Damned < ActiveRecord::Base
has_folder_attachments :for_real
end
damn = Damned.new
puts damn.physical_path # => nil
puts damn.dice # => nil
You are mixing instance and (meta)class context when using the two variables. Both variables are set their values in methods that are run in the class context (more precisely in the context of the metaclass). Thus, you cannot access these variables (and their attr_reader
s) in an instance context.
For the attr_reader
s to work, you have to move them to the class context and access them from there:
module FolderAttachments
module ClassMethods
...
attr_reader :physical_path
end
end
module ActiveRecord
class Base
...
class << self
attr_reader :dice
end
end
end
damn = Damned.new
damn.class.physical_path # => :for_real
damn.class.dice # => true
Or you may also add instance-level readers that delegate to the class-level readers so that you can access them also in instance context:
module FolderAttachments
module ClassMethods
...
attr_reader :physical_path
end
def physical_path
self.class.physical_path
end
end
module ActiveRecord
class Base
...
class << self
attr_reader :dice
end
def dice
self.class.dice
end
end
end
damn = Damned.new
damn.physical_path # => :for_real
damn.dice # => true