Skip to content

adds attr_private to ActiveRecord::Base allowing for better defensive code

License

Notifications You must be signed in to change notification settings

copypastel/attr_private

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AttrPrivate

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.

Advancing AttrPrivate

Currently I am trying to decide which of 3 solutions would be best.

Modify Attribute Methods

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.

Use Private Keyword with _ for ActiveRecord

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 and read_attribute :_field.
  • For some reason when using the setter you must use self.field=, and when using the getter you must use field. field= and self.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.

Use caller to Decide if Access is Allowed

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 uses allow_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.

Example

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

About

adds attr_private to ActiveRecord::Base allowing for better defensive code

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages