¿Qué es mattr_accessor en un módulo Rails?
-
06-07-2019 - |
Pregunta
Realmente no pude encontrar esto en la documentación de Rails, pero parece que 'mattr_accessor' es el corolario del Módulo para 'attr_accessor' ( getter & amp; setter) en una clase normal de Ruby .
Ej. en una clase
class User
attr_accessor :name
def set_fullname
@name = "#{self.first_name} #{self.last_name}"
end
end
Ej. en un módulo
module Authentication
mattr_accessor :current_user
def login
@current_user = session[:user_id] || nil
end
end
Este método auxiliar lo proporciona ActiveSupport .
Solución
Rails extiende Ruby con mattr_accessor
(Módulo de acceso) y cattr_accessor
(así como con _ reader
/ _writer
versiones). Como attr_accessor
de Ruby genera métodos getter / setter para instancias , cattr / mattr_accessor
proporciona métodos getter / setter en la clase o módulo nivel. Por lo tanto:
module Config
mattr_accessor :hostname
mattr_accessor :admin_email
end
es la abreviatura de:
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
Ambas versiones le permiten acceder a las variables de nivel de módulo de esta manera:
>> Config.hostname = "example.com"
>> Config.admin_email = "admin@example.com"
>> Config.hostname # => "example.com"
>> Config.admin_email # => "admin@example.com"
Otros consejos
Aquí está la fuente de cattr_accessor
Y
Aquí está la fuente de mattr_accessor
Como puede ver, son bastante idénticos.
¿Por qué hay dos versiones diferentes? A veces desea escribir cattr_accessor
en un módulo, por lo que puede usarlo para la información de configuración como Avdi menciona .
Sin embargo, cattr_accessor
no funciona en un módulo, por lo que más o menos copiaron el código para que funcione también para los módulos.
Además, a veces es posible que desee escribir un método de clase en un módulo, de modo que siempre que cualquier clase incluya el módulo, obtenga ese método de clase, así como todos los métodos de instancia. mattr_accessor
también le permite hacer esto.
Sin embargo, en el segundo escenario, su comportamiento es bastante extraño. Observe el siguiente código, especialmente los @@ mattr_in_module
bits
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"