Rails 模块中的 mattr_accessor 是啥?

Posted

技术标签:

【中文标题】Rails 模块中的 mattr_accessor 是啥?【英文标题】:What is mattr_accessor in a Rails module?Rails 模块中的 mattr_accessor 是什么? 【发布时间】:2010-09-16 04:20:30 【问题描述】:

我在 Rails 文档中找不到这个,但似乎 'mattr_accessor''attr_accessor'Module 推论( getter & setter) 在普通的 Ruby 中。

例如。在课堂上

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 提供。

【问题讨论】:

【参考方案1】:

Rails 使用mattr_accessor(模块访问器)和cattr_accessor(以及_reader/_writer 版本)扩展了Ruby。由于 Ruby 的 attr_accessorinstances 生成 getter/setter 方法,cattr/mattr_accessorclassmodule 级别提供 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"

【讨论】:

在您的示例中,您解释说mattr_accessor 是类实例变量的缩写(@variables),但源代码似乎显示它们实际上是在设置/读取类变量。你能解释一下这个区别吗?【参考方案2】:

Here's the source for cattr_accessor

还有

Here's the source for mattr_accessor

如您所见,它们几乎完全相同。

至于为什么会有两个不同的版本?有时您想在模块中写入cattr_accessor,以便将其用于配置信息like Avdi mentions。 但是,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)时,这是一个让我很难受的问题。一旦类将它们设置为一种方式,另一种方式将它们设置为不同的方式,从而创建无效链接。 在最新版本的 Rails 中,cattr_* 现在是 mattr_* 的别名。见cattr_accessor source

以上是关于Rails 模块中的 mattr_accessor 是啥?的主要内容,如果未能解决你的问题,请参考以下文章

外部模块中的 Rails Resque 未定义方法错误

了解 Ruby on Rails 6 中的路由 + 模块/类名称 [以及在此上下文中模块是啥]

Rails 在控制器中扩展模块

如何在 Rails 中正确使用控制器辅助模块,以及如何连接这些辅助模块?

Rails 的 ActiveRecord 序列化:attr 方法给出“缺少类或模块错误”

Rails 单个包含多个类