Not at a glance, but there are some major differences between RoR class-level accessors

Comparison of class level accessors in Ruby On Rails

Błażej Kosmowski
Jul 24, 2017 · 2 min read

attr_accessor is very useful macro that provides a getter and setter for an instance variable. Sometimes we would like to achieve the same effect, yet for class variable — useful way to make our class configurable. There are at least three ways we can approach this problem: attr_accessor, cattr_accessor and class_attribute. All of those practically work the same way if we do not use inheritance, however when inheritance comes into play, there are some significant differences.

attr_accessor — when we do not want value to be inherited

In this scenario we take advantage of regular attr_accessor, but on the class level. Using attr_accessor allows us to define variables for each of child classes, but values set in parent classes are not inherited. Each child class has attribute value set to nil initially.

class Parent
class << self
attr_accessor :foo
end
end
class Child < Parent
end
Parent.foo = 100
Child.foo #=> nil // Value was not inherited
Child.foo = 200
Child.foo #=> 200
Parent.foo #=> 100 // Changing value in child class does not affect parent class

cattr_accessor — when we do want value to be shared across all classes

In this case we use cattr_accessor to inherit value of parent class variable in child classes. It is not necessary to wrap cattr_accessor declaration in class << self block. The important thing to be aware of is that redefining class variable value in child class will change it in both child and parent classes.

class Parent
cattr_accessor :foo
end
class Child < Parent
end
class Grandchild < Child
end
Parent.foo = 100
Child.foo #=> 100
Child.foo = 200
Child.foo #=> 200
Parent.foo #=> 200 // Value propagated up in inheritance tree
Grandchild.foo #=> 200 // Value propagated down in inheritance tree

class_attribute — when we want value to be inherited and overwritable without affecting parent classes

In my opinion the most expected scenario. Using class_attribute causes variable value from parent class to be inherited, yet we can safely redefine it in child class without affecting parent class.

class Parent
class_attribute :foo
end
class Child < Parent
end
class Grandchild < Child
end
Parent.foo = 100
Child.foo #=> 100 // Value is inherited
Child.foo = 200
Child.foo #=> 200
Parent.foo #=> 100 // Redefined value does not affect parent class
Grandchild.foo #=> 200 // Redefined value is inherited in child class

Błażej Kosmowski

Written by

RubyOnRails craftsman @ selleo.com

selleo

selleo

Experienced Ruby On Rails, Elixir, Node.js, Ember.js, React & React Native developers ready to join your team or build your next project.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade