Skip to content

Ability to use the_role for per user ACL.

Andy Reilly edited this page May 24, 2018 · 5 revisions

Why not per-user roles?

In building certain apps I know it would be advantageous to be able to define all of the things a user can do

in their own "role". While the simplicity of levels of access defined as "admin" or "maintainer", etc. sometimes you need to be able to define fine grained ACLs per user. I think the_role is perfect for this. Here are my ideas:

  1. At its most basic you create a custom role for each user. You could do this with the_role_management_panel. But you would have to create the list of categories every time you create a new user.
  2. User already has_one :role. While a role does not currently belong to a user we don't really need to work backwards through that particular relation since .users would always only return one user. You can then add has_one :role to the user model. Also we add accepts_nested_attributes_for :role so that we can build the custom role and add it to the DB when building a new user.
  3. Storing the user_id in a role DB item could be as easy as having name: user_id, title: username, etc. 4 An interface for building the custom role for each user: Build a hash of all of your categories and perms like:

@role = {:data_imports=>{:new=>false, :index=>false, :create=>false}, :delete_photos=>{:destroy=>false, :delete_thumb=>false, :delete_photo=>false}, :static_pages=>{:home=>false, :admin_view=>false, :firefighter_view=>false, :technician_view=>false, :maintenance_view=>false, :logistics_view=>false}, :inspections=>{:new=>false, :index=>false, :create=>false, :show=>false, :get_my_inspections=>false}, :cleanings=>{:new=>false, :index=>false, :update=>false, :create=>false, :edit=>false, :show=>false, :get_my_cleanings=>false}, :users_imports=>{:new=>false, :index=>false, :create=>false}, :permissions=>{:index=>false}, :audit_trails=>{:show=>false}, :users=>{:new=>false, :index=>false, :update=>false, :create=>false, :destroy=>false, :edit=>false, :show=>false, :deactivated_users=>false}, :welcome=>{:index=>false}, :ppes=>{:new=>false, :index=>false, :update=>false, :create=>false, :destroy=>false, :edit=>false, :show=>false, :data_imports=>false, :by_tag=>false, :deactivated_ppe=>false, :my_ppe=>false, :get_tag_list=>false, :ajax_add_tag=>false, :ajax_del_tag=>false}, :repairs=>{:new=>false, :index=>false, :update=>false, :create=>false, :edit=>false, :show=>false, :get_my_repairs=>false}, :user_sessions=>{:new=>false, :create=>false, :destroy=>false}, :password_resets=>{:update=>false, :create=>false, :edit=>false}}

You can then use that to build checkboxes like:

   `<%= fields_for :role do |pf| %>
      <% @role.each do |perm, hash_of_rules| #iterate through categories %> 
        <div class="field h4 well well-sm">
        <%= label_tag perm.to_s.titleize %> :
        <% hash_of_rules.each do |rule, value| #category with rules: :value (true/false) %>
          <%= label_tag rule.to_s.titleize %>
          <%= hidden_field_tag "user[permissions][#{perm}][#{rule}]", false  # set value to false%>
          <%= check_box_tag "user[permissions][#{perm}][#{rule}]", true, ActiveRecord::Type::Boolean.new.cast(hash_of_rules[rule])  # build the checkbox with the value set according to current value in the DB. Overrides the previous "false" if checked%>
        <% end %>
        </div>
      <% end %>

    <% end %>`

So a user is created with it's own role which is based on a hash of all controller::actions that you want to apply an ACL to.

I am currently working on this and have it almost complete. I would like to then fork the_role and start on adding this functionality as an option in the role.