Rails 模块中的 mattr_accessor 是什么?

我在 Rails 文档中找不到这个,但是在一个普通的 Ruby 同学们中,“ mattr _ accessor”似乎是 “ attr _ accessor”(getter & setter)的 模组推论。

例如,在一个班级里

class User
attr_accessor :name


def set_fullname
@name = "#{self.first_name} #{self.last_name}"
end
end

在模块里

module Authentication
mattr_accessor :current_user


def login
@current_user = session[:user_id] || nil
end
end

这个助手方法由 ActiveSupport提供。

38588 次浏览

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 , cattr/mattr_accessor provide getter/setter methods at the class or 模组 level. Thus:

module Config
mattr_accessor :hostname
mattr_accessor :admin_email
end

是:

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
end
end

这两个版本都允许您像下面这样访问模块级别的变量:

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

这是 cattr_accessor的来源

还有

Here's the source for mattr_accessor

如你所见,它们几乎一模一样。

为什么会有两个不同的版本呢?有时候,您需要在模块中编写 cattr_accessor,因此您可以将其用于配置信息 like Avdi mentions
但是,cattr_accessor不能在模块中工作,所以他们或多或少地将代码复制到模块中。

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.

然而,在第二个场景中,它的行为非常奇怪

module MyModule
mattr_accessor :mattr_in_module
end


class MyClass
include MyModule
def self.get_mattr; @@mattr_in_module; end # directly access the class variable
end


MyModule.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 class
end


SecondClass.get_mattr # get it out of the OTHER class
=> "foo"