What is cattr_accesor and mattr_accessor, thread_cattr or thread_mattr in Ruby and in Rails?
In Ruby on Rails, the methods cattr_*
, mattr_*
, thread_cattr_*
, and thread_mattr_*
methods are used to define class-level and thread-safe class-level attributes and variables. These methods are provided by the ActiveSupport
library, which is a core component of Rails that provides various utility classes and methods. These methods are useful for scenarios where you want to store data at the class or module level, rather than at the instance level. In addition, the "thread" variants are useful in multi-threaded applications where you want to avoid data inconsistencies between threads.
cattr_* - Class-Level Attribute Methods
It defines methods to set a variable per class. We have three methods:
cattr_accessor
: Defines both a getter and a setter method for a class-level attribute.cattr_reader
: Defines a getter method for a class-level attribute.cattr_writer
: Defines a setter method for a class-level attribute.
# cattr_* example in Ruby
class PlainRubyClass
def self.only_readable
@@only_readable ||= 111
end
def self.only_writeable=(value)
@@only_writeable = value
end
def self.count
@@count ||= 0
end
def self.count=(value)
@@count = value
end
end
puts PlainRubyClass.count # Output: 0
PlainRubyClass.count = 10
puts PlainRubyClass.count # Output: 10
PlainRubyClass.count = 11
puts PlainRubyClass.count # Output: 11
puts PlainRubyClass.only_readable # Output: 111
# puts PlainRubyClass.only_readable = 333 # error
# puts PlainRubyClass.only_writeable # error
puts PlainRubyClass.only_writeable = 222 # Output: 222
# cattr_* example in Rails
require 'active_support/core_ext/class/attribute_accessors'
class RailsClass
cattr_accessor :count, default: 0
cattr_reader :only_readable, default: 111
cattr_writer :only_writeable, default: 222
end
puts RailsClass.count # Output: 0
RailsClass.count = 10
puts RailsClass.count # Output: 10
RailsClass.count = 11
puts RailsClass.count # Output: 11
puts RailsClass.only_readable # Output: 111
# puts RailsClass.only_readable = 333 # error
# puts RailsClass.only_writeable # error
mattr_* - Module-Level Attribute Methods
Similar to cattr_*
, but used inside modules instead of classes. These methods allow you to define module-level attributes and accessors. Currently, it's an alias of cattr_*
so it behaves the same as from above.
thread_cattr_* - Thread-Safe Class-Level Attribute Methods
Similar to cattr_*
, but the attribute values are stored separately for each thread. This ensures that changes to the attribute in one thread do not affect its value in other threads.
# thread_cattr_* in plain Ruby
module ThreadCattrAccessor
def thread_cattr_accessor(*names)
names.each do |name|
define_singleton_method(name) do
Thread.current[name]
end
define_singleton_method("#{name}=") do |value|
Thread.current[name] = value
end
end
end
end
class Current
extend ThreadCattrAccessor
thread_cattr_accessor :user
end
Current.user = "YourUser"
puts "Current thread: #{Current.user}" # => Current thread: YourUser
Thread.new { p "New thread: #{Current.user}" }.value # => "New thread: nil"
# thread_cattr_* in Rails
require 'active_support/all'
class Current
thread_cattr_accessor :user
end
Current.user = "YourUser"
puts "Current thread: #{Current.user}" # => Current thread: YourUser
Thread.new { p "New thread: #{Current.user}" }.value # => "New thread: nil"
thread_mattr_* - Thread-Safe Module-Level Attribute Methods
Currently, it's an alias of thread_cattr_accessor
, so it behaves the same as above.
Summary
Now you know what the difference is between plain Ruby solutions and Rails solutions, which are just shorthand for doing things like assigning variables per module or class or even safely per thread.
Happy coding!