John, this is a _fantastic_ point. It's certainly true that there
would be no way to use the "setter" half of a private attr_accessor in
a regular Ruby object:
self.bar = 'baz' # violates private
bar = 'baz' # sets a local variable
But you can use the "getter" half:
return bar.dup # return a defensive copy of the instance variable
I consider Ruby's definition of "private" fairly crippled, but that's
not the fault of the Rails community, nor can they (we?) do much about
it.
I still think you misunderstand and mix Ruby's private and Rails'
attr_protected/attr_accessible.
class A
private
def foo
"foo"
end
end
a = A.new
a.foo
NoMethodError: private method `foo' called for #<A:0x6bae4>
So no crippling here. Note that you can still access foo if you really wan:
a.send(:foo)
=> "foo"
This is Ruby where we WANT to be able to do things like that.
Rails' attr_protected/attr_accessible are only there to protect you
from mass-assignment and have noting to do with private/protected.
Ruby's attr_accessor :foo will just create a getter and setter for you
if you are too lazy.
Maybe my actual use case will help clear up why I want a private
attribute. I have a single-table-inheritance model:
table products:
integer version
string name
class Product < ActiveRecord::Base
attr_private :version # if such a method existed
end
class VersionedProduct < Foo
attr_accessor :version # reveal the method
end
I wouldn't normally ask this list for usage advice, but perhaps this
case will inform design.
The simple answer is: Just don't call version on products! It's your
code and you know where you use it.
If you really want to stop using version:
class Product < ActiveRecord::Base
def version
raise 'private'
end
end
class VersionedProduct < Product
def version
attributes[:version]
end
end
You could do the same for the setter or even write your attr_private
method that will generate the getters/setters.
But again, I see no point in doing so.
Jonathan