What is mattr_accessor in a Rails module? What is mattr_accessor in a Rails module? ruby ruby

What is mattr_accessor in a Rails module?


Rails extends Ruby with both mattr_accessor (Module accessor) and cattr_accessor (as well as _reader/_writer versions). As Ruby's attr_accessor generates getter/setter methods for instances, cattr/mattr_accessor provide getter/setter methods at the class or module level. Thus:

module Config  mattr_accessor :hostname  mattr_accessor :admin_emailend

is short for:

module Config  def self.hostname    @hostname  end  def self.hostname=(hostname)    @hostname = hostname  end  def self.admin_email    @admin_email  end  def self.admin_email=(admin_email)    @admin_email = admin_email  endend

Both versions allow you to access the module-level variables like so:

>> Config.hostname = "example.com">> Config.admin_email = "admin@example.com">> Config.hostname # => "example.com">> Config.admin_email # => "admin@example.com"


Here's the source for cattr_accessor

And

Here's the source for mattr_accessor

As you can see, they're pretty much identical.

As to why there are two different versions? Sometimes you want to write cattr_accessor in a module, so you can use it for configuration info like Avdi mentions.
However, cattr_accessor doesn't work in a module, so they more or less copied the code over to work for modules also.

Additionally, sometimes you might want to write a class method in a module, such that whenever any class includes the module, it gets that class method as well as all the instance methods. mattr_accessor also lets you do this.

However, in the second scenario, it's behaviour is pretty strange. Observe the following code, particularly note the @@mattr_in_module bits

module MyModule  mattr_accessor :mattr_in_moduleendclass MyClass  include MyModule  def self.get_mattr; @@mattr_in_module; end # directly access the class variableendMyModule.mattr_in_module = 'foo' # set it on the module=> "foo"MyClass.get_mattr # get it out of the class=> "foo"class SecondClass  include MyModule  def self.get_mattr; @@mattr_in_module; end # again directly access the class variable in a different classendSecondClass.get_mattr # get it out of the OTHER class=> "foo"