Cos'è mattr_accessor in un modulo Rails?


107

Non sono riuscito a trovarlo nella documentazione di Rails ma sembra che 'mattr_accessor' sia il corollario del modulo per 'attr_accessor' (getter & setter) in una normale classe Ruby .

Per esempio. in una classe

class User
  attr_accessor :name

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

Per esempio. in un modulo

module Authentication
  mattr_accessor :current_user

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

Questo metodo di supporto è fornito da ActiveSupport .

Risposte:


181

Rails estende Ruby sia con mattr_accessor(Module accessor) che cattr_accessor(oltre alle versioni _ reader/ _writer). Poiché Ruby attr_accessorgenera metodi getter / setter per le istanze , cattr/mattr_accessorfornisci metodi getter / setter a livello di classe o modulo . Così:

module Config
  mattr_accessor :hostname
  mattr_accessor :admin_email
end

è l'abbreviazione di:

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

Entrambe le versioni ti consentono di accedere alle variabili a livello di modulo in questo modo:

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

1
Nei tuoi esempi, spieghi che mattr_accessorsarebbe l'abbreviazione di variabili di istanza di classe @variable, ma il codice sorgente sembra rivelare che in realtà stanno impostando / leggendo variabili di classe. Potresti spiegare questa differenza?
sandre89

38

Ecco la fonte per cattr_accessor

E

Ecco la fonte per mattr_accessor

Come puoi vedere, sono praticamente identici.

Quanto al motivo per cui ci sono due versioni diverse? A volte vuoi scrivere cattr_accessorin un modulo, quindi puoi usarlo per informazioni di configurazione come menziona Avdi .
Tuttavia, cattr_accessornon funziona in un modulo, quindi hanno più o meno copiato il codice per lavorare anche con i moduli.

Inoltre, a volte potresti voler scrivere un metodo di classe in un modulo, in modo che ogni volta che una classe include il modulo, ottiene quel metodo di classe e tutti i metodi di istanza. mattr_accessorti consente anche di farlo.

Tuttavia, nel secondo scenario, il suo comportamento è piuttosto strano. Osservare il codice seguente, in particolare notare i @@mattr_in_modulebit

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"

Questo è stato un trucco che mi ha colpito abbastanza duramente quando si imposta direttamente default_url_options (un mattr_accessor). Una volta che la classe li avrebbe impostati in un modo e un altro li avrebbe impostati in un modo diverso, creando così collegamenti non validi.
Eric Davis,

Nell'ultima versione di Rails cattr_*ora ci sono alias per mattr_*. Vedi la cattr_accessorfonte
ouranos
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.