[英]Is it possible to make a class_attribute private or protected in Rails?
I have a situation where I need a variable (eg foo
) which is used internally within a class (eg Parent
) and sub-classes (eg Child
).我有一种情况,我需要一个在 class (例如
Parent
)和子类(例如Child
)内部使用的变量(例如foo
)。 In my case, I'm using Single Table Inheritance.就我而言,我使用的是单表 Inheritance。
Child
should inherit the variable foo
from Parent
if Child
does not set foo
.如果
Child
未设置foo
,则Child
应从Parent
继承变量foo
。 If Child
does set foo
, that value should only change foo
for Child
but not in Parent
.如果
Child
确实设置了foo
,则该值应该只更改Child
的foo
而不是Parent
。 This seems like a clear cut case for class_attribute .这似乎是class_attribute的一个明确案例。
The problem is that class_attribute
is not respecting a private
or protected
keyword, so foo
can be accessed from outside of Parent
and Child
, eg from the console:问题是
class_attribute
不尊重private
或protected
关键字,因此foo
可以从Parent
和Child
外部访问,例如从控制台:
# Now
Parent.foo
=> "Foo"
Child.foo
=> "Foo"/"Bar"
# What I want
Parent.foo
=> 'method_missing': protected method 'foo' called for Parent:Class (NoMethodError)
Child.foo
=> 'method_missing': protected method 'foo' called for Child:Class (NoMethodError)
I'm wondering how to achieve the setup I've described above, including solutions other that class_attribute
.我想知道如何实现我上面描述的设置,包括
class_attribute
以外的解决方案。 Note, setting instance_accessor
, instance_writer
, and instance_reader
had no effect.请注意,设置
instance_accessor
、 instance_writer
和instance_reader
无效。 Also note that a class instance variable will not work since Child
will not inherit a value for foo
from Parent
.另请注意, class 实例变量将不起作用,因为
Child
不会从Parent
继承foo
的值。
class Parent < ApplicationRecord
private
class_attribute :foo, default: "Foo"
end
class Child < Parent
# Child may or may not set :foo. If not, the value should be inherited from Parent.
# Setting :foo in Child should NOT change the value of Parent, hence using class_attribute.
# class_attribute :foo, default: "Bar"
end
I think this meets your needs, if I have understood them correctly: Take a look:如果我理解正确的话,我认为这可以满足您的需求:看看:
class Parent
@@foo = "parent foo"
class << self
private
def foo
@@foo
end
end
end
class Child < Parent
@@foo = "child foo"
end
class AnotherChild < Parent
@@foo = "another child foo"
class << self
def foo
@@foo
end
end
end
puts Parent.foo # private
puts Parent.send(:foo) # private, but accessible via .send
puts Child.send(:foo) # inherits from Parent, => "parent foo"
puts Child.foo # private method
puts AnotherChild.foo # defined in subclass => "child foo"
The class attributes (@@...) are accessed via getters def foo...
, and the getters are constrained by the private
keyword to control the access as you expressed. class 属性(@@...)通过 getter
def foo...
访问,并且 getter 受private
关键字的约束,以控制您表达的访问。
The following should work.以下应该工作。 It uses class instance variables instead of class variables, which can be a bit tricky to implement .
它使用 class 实例变量而不是 class 变量,这可能有点难以实现。
class Parent < ApplicationRecord
@foo = "Parent"
class << self
private
# This will try to get the class instance variable @foo on the current class,
# trying each parent until base_class is reached.
def foo
if self == base_class
@foo
else
@foo || superclass.send(:foo)
end
end
end
end
class Child < Parent
@foo = "Child"
end
class DeepChild < Child
end
puts Parent.foo # private method error
puts Parent.send(:foo) # private, but accessible via .send
puts Child.foo # private methode error
puts Child.send(:foo) # private, but accessible via .send. Child's @foo || Parent's @foo
puts DeepChild.foo # private method error
puts DeepChild.send(:foo) # private, but accessible via .send. DeepChild's @foo || Child's @foo || Parent's @foo
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.