🐘
【Rails】class_attribute について
概要
Rails の ActiveSupport の機能の一つである、 class_attribute
について書きました!
定数、クラス変数との違いについて触れているので、参考になれば嬉しいです!
クラスに属性をもたせることができる
class Oya
class_attribute(:some_attribute, default: 1)
end
Oya.some_attribute
=> 1
メソッド内で使うときはこんな感じ
class Oya
class_attribute(:some_attribute, default: 1)
def some_method
self.some_attribute
end
end
Oya.new.some_method
=> 1
instance_accessor
オプションを false にするとインスタンスレベルでの呼び出しや変更ができなくなります。
class Oya
class_attribute(:some_attribute, default: 1, instance_accessor: false)
def some_method
self.some_attribute
end
end
Oya.new.some_attribute
NoMethodError: undefined method `some_attribute' for #<Oya:0x0000aaaaed86b260>
Oya.new.some_method
NoMethodError: undefined method `some_attribute' for #<Oya:0x0000aaaaed43c2e8>
定数と違い、メソッド内で変更できる
定数はメソッド内で値を変更するコードが存在すると、定義時に dynamic constant assignment
が発生します。
class Oya
SOME_CONSTANT = 1
def some_method
SOME_CONSTANT = 2 # dynamic constant assignment が発生
end
end
class_attribute ではメソッド内での上書きができます。
class Oya
class_attribute(:some_attribute, default: 1)
def some_method
self.some_attribute = 2
end
def some_method2
self.some_attribute
end
def some_method3
self.class.some_attribute
end
end
# インスタンスから呼び出される attribute のみ値が変更される。
oya = Oya.new
oya.some_method
=> 2
oya.some_method2
=> 2
# もとのクラスの attribute の値は変わらない。
Oya.some_attribute
=> 1
サブクラスで値を変更してもスーパークラスに影響を与えない
スーパークラスの属性をサブクラスに継承したい場合、クラス変数(@@
)を使うことができます。
しかし、クラス変数はサブクラス内で変更された際に、スーパークラスのクラス変数も変更してしまうため、予期せぬバグが発生しやすいです。
余談ですがクラス変数を呼び出すにはゲッター(self.some_attribute
)が必要です。
class Oya
@@some_attribute = 1
def self.some_attribute
@@some_attribute
end
end
class Ko < Oya
def change_attribute
@@some_attribute = 2
end
end
Oya.some_attribute
=> 1
Ko.some_attribute
=> 1
Ko.new.change_attribute
=> 2
# スーパークラスまで値が変わってしまう。
Oya.some_attribute
=> 2
class_attribute なら、サブクラスで値を変更したとしても、スーパークラスには影響を与えません。
class Oya
class_attribute(:some_attribute, default: 1)
end
class Ko < Oya
def change_attribute
self.some_attribute = 2
end
end
Oya.some_attribute
=> 1
Ko.some_attribute
=> 1
Ko.new.change_attribute
=> 2
# スーパークラスは変わらない。
Oya.some_attribute
=> 1
まとめ
サブクラスでのメソッド内での変更 | 呼び出し時のゲッター | |
---|---|---|
クラス変数 | スーパークラスに影響する | 必要 |
定数 | 定義時エラーする | - |
class_attribute | スーパークラスに影響しない | 不要 |
Discussion