February 27, 2018
This blog is part of our Rails 5.2 series.
When DHH introduced
support for specifying a default value for class_attribute,
Genadi Samokovarov
brought to notice
that the module and class attribute accessor macros also support specifying a
default value but using a block and not with a default
option.
To have consistent and symmetrical behaviour across all the attribute
extensions, it was decided to support specifying a default value using default
option for all the module and class attribute macros as well.
mattr_accessor
, mattr_reader
and mattr_writer
macros generate getter and
setter methods at the module level.
Similarly, cattr_accessor
, cattr_reader
, and cattr_writer
macros generate
getter and setter methods at the class level.
Before Rails 5.2, this is how we would set the default values for the module and class attribute accessor macros.
module ActivityLoggerHelper
mattr_accessor :colorize_logs
mattr_writer :log_ip { false }
self.colorize_logs = true
end
class ActivityLogger
include ActivityLoggerHelper
cattr_writer :logger { Logger.new(STDOUT) }
cattr_accessor :level
cattr_accessor :settings
cattr_reader :pid { Process.pid }
@@level = Logger::DEBUG
self.settings = {}
end
We can still set a default value of a module or class attribute accessor by
providing a block. In this
pull request, support for
specifying a default value using a new default
option has been introduced.
So instead of
cattr_writer :logger { Logger.new(STDOUT) }
or
cattr_writer :logger
self.logger = Logger.new(STDOUT)
or
cattr_writer :logger
@@logger = Logger.new(STDOUT)
we can now easily write
cattr_writer :logger, default: Logger.new(STDOUT)
Same applies to the other attribute accessor macros like mattr_accessor
,
mattr_reader
, mattr_writer
, cattr_accessor
, and cattr_reader
.
Note that, the old way of specifying a default value using the block syntax will work but will not be documented anywhere.
Also, note that if we try to set the default value by both ways i.e. by
providing a block as well as by specifying a default
option; the value
provided by default
option will always take the precedence.
mattr_accessor(:colorize_logs, default: true) { false }
Here, @@colorize_logs
would be set with true
as per the above precedence
rule.
Here is a test which verifies this behavior.
Finally, here is simplified version using the new default
option.
module ActivityLoggerHelper
mattr_accessor :colorize_logs, default: true
mattr_writer :log_ip, default: false
end
class ActivityLogger
include ActivityLoggerHelper
cattr_writer :logger, default: Logger.new(STDOUT)
cattr_accessor :level, default: Logger::DEBUG
cattr_accessor :settings, default: {}
cattr_reader :pid, default: Process.pid
end
If this blog was helpful, check out our full blog archive.