Apa mattr_accessor dalam modul Rails?

107

Saya tidak dapat benar-benar menemukan ini dalam dokumentasi Rails tetapi sepertinya 'mattr_accessor' adalah wajar Modul untuk 'attr_accessor' (getter & setter) di kelas Ruby normal .

Misalnya. di kelas

class User
  attr_accessor :name

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

Misalnya. dalam sebuah modul

module Authentication
  mattr_accessor :current_user

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

Metode pembantu ini disediakan oleh ActiveSupport .

JasonOng
sumber

Jawaban:

181

Rails memperluas Ruby dengan mattr_accessor(pengakses modul) dan cattr_accessor(serta _ reader/ _writerversi). Saat Ruby attr_accessormenghasilkan metode pengambil / penyetel untuk instance , cattr/mattr_accessorsediakan metode pengambil / penyetel di tingkat kelas atau modul . Jadi:

module Config
  mattr_accessor :hostname
  mattr_accessor :admin_email
end

adalah kependekan dari:

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

Kedua versi memungkinkan Anda mengakses variabel level modul seperti:

>> Config.hostname = "example.com"
>> Config.admin_email = "[email protected]"
>> Config.hostname # => "example.com"
>> Config.admin_email # => "[email protected]"
Avdi
sumber
1
Dalam contoh Anda, Anda menjelaskan bahwa itu mattr_accessorakan menjadi kependekan dari variabel instance kelas @variable, tetapi kode sumber tampaknya mengungkapkan bahwa mereka sebenarnya menyetel / membaca variabel kelas. Bisakah Anda menjelaskan perbedaan ini?
sandre89
38

Ini sumbernya cattr_accessor

Dan

Ini sumbernya mattr_accessor

Seperti yang Anda lihat, mereka sangat identik.

Mengapa ada dua versi berbeda? Terkadang Anda ingin menulis cattr_accessordalam modul, sehingga Anda dapat menggunakannya untuk info konfigurasi seperti yang disebutkan Avdi .
Namun, cattr_accessortidak berfungsi dalam modul, jadi mereka lebih atau kurang menyalin kode untuk bekerja untuk modul juga.

Selain itu, terkadang Anda mungkin ingin menulis metode kelas dalam modul, sehingga setiap kali kelas menyertakan modul, ia mendapatkan metode kelas tersebut serta semua metode instance. mattr_accessorjuga memungkinkan Anda melakukan ini.

Namun, dalam skenario kedua, perilakunya cukup aneh. Perhatikan kode berikut, terutama perhatikan @@mattr_in_modulebit - bitnya

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
sumber
Ini adalah gotcha yang menggigit saya cukup keras saat menyetel default_url_options secara langsung (a mattr_accessor). Setelah kelas mengaturnya dengan satu cara dan yang lain akan mengaturnya dengan cara yang berbeda, sehingga membuat tautan tidak valid.
Eric Davis
Dalam versi terbaru Rails cattr_*sekarang alias untuk mattr_*. Lihat cattr_accessorsumbernya
ouranos