ruby-on-railsrubyinstance-variablesattr-accessor

Share data between methods


I have this module, which gets included in a class:

module MyModule

    def self.included base
        base.extend ClassMethods
    end

    module ClassMethods
        def my_module_method data
            include MyModule::InstanceMethods

            after_save :my_module_process

            attr_accessor :shared_data
            shared_data = data
            # instance_variable_set :@shared_data, data
        end
    end

    module InstanceMethods

        private

        def my_module_process
            raise self.shared_data.inspect
            # raise instance_variable_get(:@shared_data).inspect
        end

    end

end

I want to use the data (parameter) passed to my_module_method within my_module_process. I've used attr_accessor as well as instance variables, but either of them return nil.


Solution

  • Since you're using rails, your module can be greatly simplified by making it a AS::Concern

    module MyModule
      extend ActiveSupport::Concern
    
      included do
        # after_save :my_module_process # or whatever
        cattr_accessor :shared_data
      end
    
      module ClassMethods
        def my_module_method(data)
          self.shared_data = data
        end
      end
    
      def my_module_process
        "I got this shared data: #{self.class.shared_data}"
      end
    end
    

    The key points here are:

    Usage:

    class Foo
      include MyModule
    end
    
    f = Foo.new
    f.my_module_process # => "I got this shared data: "
    Foo.my_module_method({foo: 'bar'})
    f.my_module_process # => "I got this shared data: {:foo=>\"bar\"}"
    

    I've used attr_accessor as well as instance variables, but either of them return nil.

    In ruby, it is super-important to know what is self at any given moment. This is what defines the methods and instance variables available to you. As an exercise, I offer you to find out, why user.name returns nil here (and how to fix it).

    class User
      @name = 'Joe'
    
      def name
        @name
      end
    end
    
    user = User.new
    user.name # => nil