Was ist mattr_accessor in einem Rails-Modul?

107

Ich konnte nicht wirklich diese Dokumentation in Rails finden , aber es scheint , wie ‚mattr_accessor‘ ist das Modul logische Folge für ‚attr_accessor‘ (Getter & Setter) in einer normalen Ruby - Klasse .

Z.B. in einer Klasse

class User
  attr_accessor :name

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

Z.B. in einem Modul

module Authentication
  mattr_accessor :current_user

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

Diese Hilfsmethode wird von ActiveSupport bereitgestellt .

JasonOng
quelle

Antworten:

181

Rails erweitert Ruby sowohl um mattr_accessor(Module Accessor) cattr_accessorals auch (sowie _ reader/ _writerVersionen). Wenn Ruby attr_accessorGetter / Setter-Methoden für Instanzen generiert , cattr/mattr_accessorstellen Sie Getter / Setter-Methoden auf Klassen- oder Modulebene bereit . So:

module Config
  mattr_accessor :hostname
  mattr_accessor :admin_email
end

Kurzform für:

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

In beiden Versionen können Sie wie folgt auf Variablen auf Modulebene zugreifen:

>> Config.hostname = "example.com"
>> Config.admin_email = "[email protected]"
>> Config.hostname # => "example.com"
>> Config.admin_email # => "[email protected]"
Avdi
quelle
1
In Ihren Beispielen erklären Sie, dass mattr_accessordies für Klasseninstanzvariablen kurz ist @variable, aber der Quellcode scheint zu zeigen, dass sie tatsächlich Klassenvariablen setzen / lesen. Könnten Sie bitte diesen Unterschied erklären?
Sandre89
38

Hier ist die Quelle für cattr_accessor

Und

Hier ist die Quelle für mattr_accessor

Wie Sie sehen können, sind sie ziemlich identisch.

Warum gibt es zwei verschiedene Versionen? Manchmal möchten Sie cattr_accessorin ein Modul schreiben , damit Sie es für Konfigurationsinformationen wie Avdi-Erwähnungen verwenden können .
Funktioniert jedoch cattr_accessornicht in einem Modul, sodass der Code mehr oder weniger kopiert wurde, um auch für Module zu funktionieren.

Außerdem möchten Sie manchmal eine Klassenmethode in ein Modul schreiben, sodass jedes Mal, wenn eine Klasse das Modul enthält, diese Klassenmethode sowie alle Instanzmethoden abgerufen werden. mattr_accessorSie können dies auch tun.

Im zweiten Szenario ist das Verhalten jedoch ziemlich seltsam. Beachten Sie den folgenden Code, insbesondere die @@mattr_in_moduleBits

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"
Orion Edwards
quelle
Dies war ein Problem, das mich ziemlich hart gebissen hat, als ich default_url_options direkt gesetzt habe (ein mattr_accessor). Sobald die Klasse sie in eine Richtung und eine andere in eine andere Richtung gesetzt hat, werden ungültige Links erstellt.
Eric Davis
In der neuesten Version von Rails cattr_*sind jetzt Aliase für mattr_*. Siehe die cattr_accessorQuelle
ouranos