Che cos'è mattr_accessor in un modulo Rails?
-
06-07-2019 - |
Domanda
Non sono riuscito a trovarlo nella documentazione di Rails ma sembra che 'mattr_accessor' sia il Modulo corollario per 'attr_accessor' ( getter & amp; setter) in una normale classe .
Eg. in una classe
class User
attr_accessor :name
def set_fullname
@name = "#{self.first_name} #{self.last_name}"
end
end
Eg. 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 .
Soluzione
Rails estende Ruby sia con mattr_accessor
(modulo accessor) che cattr_accessor
(così come _ reader
/ _writer
versioni). Dato che attr_accessor
di Ruby genera metodi getter / setter per istanze , cattr / mattr_accessor
fornisce metodi getter / setter nella 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 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"
Altri suggerimenti
Ecco la fonte per cattr_accessor
E
Ecco la fonte per mattr_accessor
Come puoi vedere, sono praticamente identici.
Perché ci sono due versioni diverse? A volte vuoi scrivere cattr_accessor
in un modulo, quindi puoi usarlo per informazioni sulla configurazione come menziona Avdi .
Tuttavia, cattr_accessor
non funziona in un modulo, quindi hanno più o meno copiato il codice per funzionare anche per i moduli.
Inoltre, a volte potresti voler scrivere un metodo di classe in un modulo, in modo tale che ogni qualvolta una classe includa il modulo, ottenga quel metodo di classe così come tutti i metodi di istanza. Anche mattr_accessor
ti consente di farlo.
Tuttavia, nel secondo scenario, il suo comportamento è piuttosto strano. Osservare il codice seguente, in particolare i bit @@ 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"