Mattr_accessor trong mô-đun Rails là gì?


107

Tôi thực sự không thể tìm thấy điều này trong tài liệu Rails nhưng có vẻ như 'mattr_accessor' là hệ quả Mô-đun cho 'attr_accessor' (getter & setter) trong một lớp Ruby bình thường .

Ví dụ. trong một lớp học

class User
  attr_accessor :name

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

Ví dụ. trong một mô-đun

module Authentication
  mattr_accessor :current_user

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

Phương thức trợ giúp này được cung cấp bởi ActiveSupport .

Câu trả lời:


181

Rails mở rộng Ruby với cả mattr_accessor(Trình truy cập mô-đun) và cattr_accessor(cũng như các phiên bản _ reader/ _writer). Khi Ruby attr_accessortạo ra các phương thức getter / setter cho các phiên bản , hãy cattr/mattr_accessorcung cấp các phương thức getter / setter ở cấp độ lớp hoặc mô-đun . Như vậy:

module Config
  mattr_accessor :hostname
  mattr_accessor :admin_email
end

là viết tắt của:

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

Cả hai phiên bản đều cho phép bạn truy cập các biến cấp mô-đun như sau:

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

1
Trong các ví dụ của bạn, bạn giải thích rằng đó mattr_accessorsẽ là viết tắt của ( @variablecác) biến cá thể lớp , nhưng mã nguồn dường như tiết lộ rằng chúng thực sự đang thiết lập / đọc các biến lớp. Bạn có thể vui lòng giải thích sự khác biệt này?
sandre89

38

Đây là nguồn cho cattr_accessor

Đây là nguồn cho mattr_accessor

Như bạn có thể thấy, chúng khá giống nhau.

Tại sao có hai phiên bản khác nhau? Đôi khi bạn muốn viết cattr_accessortrong một mô-đun, vì vậy bạn có thể sử dụng nó cho thông tin cấu hình như Avdi đã đề cập .
Tuy nhiên, cattr_accessorkhông hoạt động trong một mô-đun, vì vậy ít nhiều họ đã sao chép mã sang đó để hoạt động cho cả mô-đun.

Ngoài ra, đôi khi bạn có thể muốn viết một phương thức lớp trong một mô-đun, chẳng hạn như bất cứ khi nào bất kỳ lớp nào bao gồm mô-đun, nó sẽ nhận được phương thức lớp đó cũng như tất cả các phương thức phiên bản. mattr_accessorcũng cho phép bạn làm điều này.

Tuy nhiên, trong kịch bản thứ hai, hành vi của nó khá kỳ lạ. Quan sát đoạn mã sau, đặc biệt lưu ý các @@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"

Đây là một lỗi khiến tôi khá khó khăn khi thiết lập trực tiếp default_url_options (một mattr_accessor). Một khi lớp sẽ đặt chúng theo cách này và lớp khác sẽ đặt chúng theo cách khác, do đó tạo ra các liên kết không hợp lệ.
Eric Davis

Trong phiên bản mới nhất của Rails cattr_*bây giờ là bí danh cho mattr_*. Xem cattr_accessornguồn
ouranos
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.