Rails模块中的mattr_accessor是什么?

120

我在 Rails 文档中找不到类似的内容,但好像 'mattr_accessor' 是一个普通 Ruby '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 提供。


这些文档比这里的答案更好。 - undefined
2个回答

197

Rails通过mattr_accessor(模块访问器)和cattr_accessor扩展了Ruby语言,同时还包含了_reader/_writer版本。由于Ruby的attr_accessor会为实例对象生成getter/setter方法,cattr/mattr_accessor则会提供类或模块级别的getter/setter方法。因此:

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"

2
在你的例子中,你解释说 mattr_accessor 是类实例变量(@variable)的简称,但源代码似乎揭示它们实际上是设置/读取类变量。你能否解释一下这种差异? - sandre89

40

这里是cattr_accessor的源代码

以及

这里是mattr_accessor的源代码

你会发现,它们几乎是相同的。

为什么会有两个不同的版本呢?有时候您可能想要在模块中编写cattr_accessor,这样您就可以像Avdi提到的那样将其用于配置信息。
然而,cattr_accessor在模块中不起作用,因此他们更多地是复制了该代码以使其也适用于模块。

此外,有时您可能想在模块中编写类方法,以便无论任何类是否包含该模块,它都可以获得该类方法以及所有实例方法。 mattr_accessor也可实现此功能。

但是,在第二种情况下,它的行为非常奇怪。请注意以下代码,特别是@@mattr_in_module部分。

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"

当我直接设置default_url_options(一个mattr_accessor)时,这是一个让我非常困扰的问题。一个类会以一种方式设置它们,而另一个类会以不同的方式设置它们,从而创建无效的链接。 - Eric Davis
在Rails的最新版本中,cattr_* 现在是 mattr_* 的别名。请参见 cattr_accessor 源码 - ouranos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接