Що таке mattr_accessor в модулі Rails?


107

Я справді не міг знайти це в документації на Rails, але здається, що "mattr_accessor" є наслідком модуля для "attr_accessor" (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 .

Відповіді:


181

Rails розширює Ruby як з mattr_accessor(модульним аксесуаром), так і cattr_accessor(а також з _ 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"

1
У своїх прикладах ви пояснюєте, що mattr_accessorзмінні ( @variable-и) екземплярів класу можуть бути короткими , але, схоже, вихідний код показує, що вони насправді встановлюють / читають змінні класу. Не могли б ви пояснити цю різницю?
sandre89

38

Ось джерело для cattr_accessor

І

Ось джерело для mattr_accessor

Як бачите, вони майже однакові.

Щодо того, чому існують дві різні версії? Іноді потрібно писати cattr_accessorв модулі, тому ви можете використовувати його для інформації про конфігурацію, як Авді згадує .
Однак 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джерело
ouranos
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.