Permissionable Attributes ======================== Plugin Home: http://code.google.com/p/permissionable-attributes/ Author: Ben Mabey, ben AT benmabey.com, http://www.benmabey.com Permissionable Attributes allows you to declare which attributes of a model have permissions associated with them and what those permissions are. The best example of where you would use this plugin is for a community site where you have certain attributes on a user model that are only viewable to certain people. For example, some attributes might be viewable to the entire public, while others might only be available to that user's friends. The plugin only supports mutually exclusive permissions. Meaning, an attribute is either just viewable by the public or just viewable by friends but not both. However, if an attribute is viewable by the public your helpers should probably be smart enough to that friends should also be able to view them. Here is an example of how to use it: class User << AR:Base include PermissionableAttributes # Note, you need to include it. has_attributes_with_permissions do |config| config.attributes = %w[first_name last_name email age] config.permissions = [:viewable_by_public, :viewable_by_friends, :viewable_by_no_one] config.permission_defaults = {:first_name => :viewable_by_friends, :all => :viewable_by_public} # Note how the :all serves as a general case default for attributes not specified. end end This way requires that for each permissionable attribute there needs to be a DB column that corresponds to that field for it's permissions (stored as an int). It should be named #{field_name}_permissions. So like this: first_name_permissions, last_name_permissions, email_permissions, age_permissions, etc... If you have a lot of attributes with permissions and don't liek the idea of having a separate field for each of there permissions Permissionable Attributes also supports storing all permission information in one int using bit masks (see below for more information.) Permissionable Attributes will generate some methods and set some constants for you. Observe: A constant is set on the model with the attribute defaults so you can use them in a migration. This is nice because it allows you to declare the defaults in the model and then use them in the migration to set the actual default DB value >> User::ATTRIBUTES_PERMISSION_DEFAULTS[:first_name] # Useful in migrations; Use the DB to store the defaults. => 1 Every attribute gets a predicate method for each permission defined: >> u = User.new => # >> u.first_name_viewable_by_friends? => true >> u.first_name_viewable_by_public? => false >> u.first_name_viewable_by_no_one? => false You can also set the fields permission using the human readable permission symbol: >> u.first_name_permissions = :viewable_by_public => :viewable_by_public >> u.first_name_viewable_by_friends? => false >> u.first_name_viewable_by_public? => true Honestly, though using the numbers that map to the permissions is more useful when it comes to forms: >> u.first_name_permissions = 2 => 2 >> u.first_name_viewable_by_public? => false >> u.first_name_viewable_by_no_one? => true How do you know what numbers map to your permissions? Well, a nice little constant is set on the model for your use in a dropdown, or other use in a form: >> User::ATTRIBUTE_PERMISSION_VALUES => [["Viewable by public", 0], ["Viewable by friends", 1], ["Viewable by no one", 2]] Using the bitmask version ======================== If you want to store all of your permission data in one field you can set Permissionable Attributes to use bitmasks to accomplish that goal: class User << AR:Base include PermissionableAttributes has_attributes_with_permissions do |config| config.attributes = %w[first_name last_name email age] config.permissions = [:viewable_by_public, :viewable_by_friends, :viewable_by_no_one] config.permission_defaults = {:first_name => :viewable_by_friends, :all => :viewable_by_public} config.use_bitmask end end You must create a field called "attributes_permissions", or pass in your own name like so: config.use_bitmask :user_permissions All of the same methods and constants are added in this version with the addition of one method: >> User.default_permissions => 10565 Using this method you can still easily set the model's default permission settings in the migration, like so: t.integer :attributes_permissions, :default => User.default_permissions Again, all of the same methods will be generated for the bitmask version. The big caveat with the bitmask version is the loss of flexibility in the future. If you were to add a new permission or remove one would need to regenerate the permissions for all of the fields in the DB. You also make it harder to remove attributes because the permissions are all stored sequentially in the permissions int in the same order as you lay them out in your declaration. IMPORTANT: Once you define your attributes with the bitmask version you should never change the order or remove one (once you go live.) You can append new ones but changing the order of the declaration will not magically change the placement of bits in the permissions integer in the DB. The same goes for permissions as well. If you really need to change it then you will need to regenerate the bitmask to reflect those changes. If you wish to remove an attribute from the list I would just suggest replacing it with a dummy name like :place_holder, just so the bits are still matched up with the correct attributes.