Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails: クラスレベルの3つのアクセサの使い方を比較する(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

参考: Rails API cattr_accessor -- Module
参考: Rails API class_attribute -- Class


  • 2017/10/19: 初版公開
  • 2023/07/31: 更新

Rails: クラスレベルの3つのアクセサの使い方を比較する(翻訳)

attr_accessorは、インスタンス変数のgetterとsetterを提供する非常に有用なマクロです。これと同じ効果をクラス変数でも得られれば、クラス変数でクラスを設定できて便利な場合もあります。

そのための方法として、少なくともattr_accessorcattr_accessorclass_attributeの3つのアプローチがあります。継承を使わない場合はどれも同じに使えますが、継承がからむ場合の動作はかなり異なります。

🔗 1. attr_accessor: 値を継承したくない場合に使う

この場合は通常のattr_accessorを使いますが、ここではクラスレベルで使います。attr_accessorを使うと、各子クラスに変数が定義されますが、親クラスに設定された値は継承されません。各子クラスの属性の初期値はnilに設定されます。

class Parent
 class << self
   attr_accessor :foo
 end
end
class Child < Parent 
end
Parent.foo = 100
Child.foo        #=> nil (値は継承されない)
Child.foo = 200
Child.foo        #=> 200
Parent.foo       #=> 100 (子クラスで値を変更しても親クラスの値には影響しない)

訳注

attr_accessorはRubyのメソッドです。

参考: Module#attr_accessor (Ruby 3.2 リファレンスマニュアル)

🔗 2. cattr_accessor: 値をすべてのクラスで共有したい場合に使う

この場合はcattr_accessorで親クラスの値を子クラスに継承します。この場合、cattr_accessor宣言をclass << selfブロックの内側に置く必要はありません。ここで重要なのは、子クラスでクラス変数の値を再定義すると親クラスと子クラスの両方で値が変更されるという点です。

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 (値は継承ツリーの上位に反映される)
Grandchild.foo     #=> 200 (値は継承ツリーの下位に反映される)

訳注

cattr_accessormattr_accessorのエイリアスです。

参考: Rails API mattr_accessor -- Module

🔗 3. class_attribute: 継承した値を親クラスに影響を与えずに上書き可能にしたい場合に使う

私はこのシナリオが最も有用だと思います。class_attributeを使うと親クラスの変数値が継承され、継承した値は親クラスに影響することなく子クラスで安全に再定義できます。

class Parent
  class_attribute :foo
end
class Child < Parent
end
class Grandchild < Child
end
Parent.foo = 100
Child.foo         #=> 100 (値は継承される)
Child.foo = 200 
Child.foo         #=> 200
Parent.foo        #=> 100 (値を再定義しても親クラスには影響しない)
Grandchild.foo    #=> 200 (再定義した値はその子クラスに継承される)

関連記事

TestProf: Ruby/Railsの遅いテストを診断するgem(翻訳)

Rails: N+1クエリを「バッチング」で解決するBatchLoader gem(翻訳)

Rails: render_async gemでレンダリングを高速化(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。