AttrPrivate adds the attr_private
method to ActiveRecord models. This is a tool which is meant to be used to help programmers working in teams write defensive code.
I looked at a few solutions out there and wasn’t quite satisfied with anything. ggoodale/attr_private
on github was the closest if you want to take a look.
Currently I am trying to decide which of 3 solutions would be best.
The most obvious solution would be to edit all of the attribute_methods accessors to take into account the private_attributes. Currently this is how Rails handles protected_attributes so I would try to use a similar model.
pros
- Best solution and won’t accidentally break anything.
cons
- Would take much more time then already spent.
- Not worth it unless people are really interested.
This way is the simplest to implement but results in some ugly code and requires the user to modify the database when changing between private and non-private accessors. Basically you prefix the name of the field with an underscore. You then use attr_private :field
to specify a private attribute. You get getters and setters for field=
and field
, which are declared as private and can only be used inside the model. Outside the model you can still use _field
to set it directly.
pros
- Easiest to implement and doesn’t seem that hackish.
- Gives real private functionality but still lets ActiveRecord modify the values.
cons
- Without overriding all the accessors it is possible to view the private attributes from functions like
attributes
andread_attribute :_field
. - For some reason when using the setter you must use
self.field=
, and when using the getter you must usefield
.field=
andself.field
will produce errors. I have not figured out why this is. - Still gives public access for bypassing the security using
_field
. The point of this library is to remove an accidental way of setting a field you aren’t supposed to. However the underscore may be enough that the programmer would look further into it before using it. - A lot of the code ends up having things like
if attribute == "_#{field}"
since ActiveRecord only knows the_field
version. - Would require a lot of work to do things like removing private attributes from the attributes method. If needed would probably be just as easy to go to method 1.
This way involves parsing the caller arguments to see if it is coming from a file that is allowed access. It figures out which files are allowed access via a code generator which only works on Unix machines. The code generator is run before the app is started and requires that Rails be frozen for the app.
pros
- Gets rid of the necessity for keeping track of
_
methods. - Easy to restrict more functions without changing a lot of code.
cons
allow_private_access?
is not very robust. Deciding if something deserves access is really figured out on a trial and error basis as tests are written.- Parsing the
caller
string is a pain, adding a lot of overhead to each assignment operation that usesallow_private_access?
.
If people are interested but do not like the allow_private_access
(I don’t either) then I should go to method 1 since method 2 would require just about as much work but still cause the private attributes to have a different field name accessed in the model.
class Model < ActiveRecord::Base attr_private :private_attribute # Inside the model you can set private_attribute directly def set_private_attribute(attr) self.private_attribute = attr end
# Inside the model you can get private_attribute directly def get_private_attribute self.private_attribute end end
# Outside the model you must use getters/setters to access the private methods model = Model.new model.private_attribute = "test" # => NoMethodError, private method `private_attribute=' called for #<Model:0xffffff> model.private_attribute # => NoMethodError, private method `private_attribute' called for #<Model:0xffffff>
model.set_private_attribute('test') # => 'test' model.get_private_attirbute # => 'test'
Copyright © 2009 copypastel.com, released under the MIT license