Is there a way to make Rails ActiveRecord attributes private?
By default, Ac开发者_运维问答tiveRecord takes all fields from the corresponding database table and creates public attributes for all of them.
I think that it's reasonable not to make all attributes in a model public. Even more, exposing attributes that are meant for internal use clutters the model's interface and violates the encapsulation principle.
So, is there a way to make some of the attributes literally private
?
Or, maybe I should move on to some other ORM?
Jordini was most of the way there
Most of active_record happens in method_missing. If you define the method up front, it won't hit method_missing for that method, and use yours instead (effectively overwriting, but not really)
class YourModel < ActiveRecord::Base
private
def my_private_attribute
self[:my_private_attribute]
end
def my_private_attribute=(val)
write_attribute :my_private_attribute, val
end
end
Stumbled upon this recently. If you want private writing and reading and public reading something like this
class YourModel < ActiveRecord::Base
attr_reader :attribute
private
attr_accessor :attribute
end
seems to work fine for me. You can fiddle with attr_reader, attr_writer and attr_accessor to decide what should be exposed and what should be private.
well, you could always override the methods...
class YourModel < ActiveRecord::Base
private
def my_private_attribute
self[:my_private_attribute]
end
def my_private_attribute=(val)
self[:my_private_attribute] = val
end
end
For me methods from both Otto and jordinl are working fine and make rspec for object of Class to pass:
object.should_not respond_to :attribute
But when I use jordinl method, I have a deprecation message to not write to database directly, but use attr_writer instead.
UPDATE:
But the truly "right" metod to do it turns out to be simple. Thanks to Mladen Jablanović and Christopher Creutzig from here. To make predefined method private or protected... simply redefine it:
Class Class_name
private :method_name
protected :method_name_1
end
What's important, you needn't rewrite previously defined method's logic.
You can make an existing method private:
YourClass.send(:private, :your_method)
Making the setting private does generate ActiveRecord error.
I put access control code in the overwritten method of the public setter by checking the caller:
def my_private_attribute=(val)
if (caller.first.include?('active_record/base.rb') || caller.first.include?('app/models/myclass.rb'))
self[:my_private_attribute] = val
else
raise Exception.new("Cannot set read-only attribute.")
end
end
I don't think there is 100% reliable way to do this. It's also worth checking the most popular ways to access attributes:
http://www.davidverhasselt.com/set-attributes-in-activerecord/
精彩评论