title: Implementing multiple user roles
body: <p>I've had great success using the state_machine and love the class methods it dynamically creates through just few lines of code. </p>
  
  <p>However, I'm not sure how to proceed with the system I'm creating. I'm currently developing a system where users have many roles. So it's not a simple as having a user whose state goes from <strong>unconfirmed</strong> to <strong>confirmed</strong> and then potentially to <strong>admin</strong>.</p>
  
  <p>A user now has many roles, and can be a <strong>potential</strong>, a <strong>cyclist</strong>, a <strong>coorinator</strong>, a <strong>manger</strong>, a <strong>forum admin</strong>, a <strong>store admin</strong>, a <strong>super admin</strong> and a <strong>fundraiser</strong>.</p>
  
  <p>So the hierarchy goes like this:</p>
  
  <blockquote>
    <p><strong>superadmin</strong></p>
    
    <p><strong>forum admin</strong>, <strong>store admin</strong></p>
    
    <p><strong>cyclist</strong>, <strong>coordinator</strong>, <strong>manger</strong>, <strong>fundraiser</strong></p>
    
    <p><strong>potential</strong></p>
  </blockquote>
  
  <p>However, one state machine won't cut it here, because it's completely possible that one user can have all of the above roles at the same time.</p>
  
  <p>I'm implementing my own class methods like this to sort of emulate state-machine somewhat:</p>
  
  <pre><code>class User &lt; ActiveModel::Base
      has_many :jobs
      has_many :roles, through: :jobs
  
      def role_array
          self.roles.pluck(:role)
      end
  
      def has_role?(role)
          role_array.include?(role)
      end
  
      # checking
      def is_superadmin?
          role_array.include?('superadmin')
      end
  
  
      # changing
      def add_role(role)
         self.update_attributes(accepted_at: Time.now) if self.is_only_potential?
         self.user_roles.create(role_id: Role.find_by(role: role).id ) if !self.has_role?(role)
      end
  
      def remove_role(role)
          self.user_roles.find_by( role_id: Role.find_by(role: role).id ).destroy if self.has_role?(role)
      end
  
      def make_superadmin!
          add_role('superadmin')
      end
  
      def denounce_superadmin!
          remove_role('superadmin')
      end
  
  end
  </code></pre>
  
  <p>And it's just a bit of a faff. So my questions are:</p>
  
  <p><strong>1)</strong> Am I doing it right? How would you handle users with multiple roles?</p>
  
  <p><strong>2)</strong> Even if I am doing it right, I'd like to create a state_machine-esque DSL, so when I need to create a new role, let's say 'runner', I can just do something like this in my model:</p>
  
  <pre><code>class User &lt; ActiveModel::Base
      has_many :jobs
      has_many :roles, through: :jobs
  
      multiroles initial: :potential do
          roles [:superadmin, :forum_admin, :store_admin, :cyclist, :coordinator, :manager, :fundraiser, :potential]
           # dynamically creates the above methods for getting and setting for all roles
      end
  </code></pre>
  
  <p>How should I create that multiroles method? Inside <code>lib</code>? ready to be packaged off as my first Gem?</p>
  
  <p>I have no idea how to dynamically create methods, but I'd like to start :)</p>
  
  <p>Just a thought, maybe the <code>multiroles</code> method could dynamically get all the roles via <code>Roles.all</code> and automatically add the above methods! Maybe even take care of the <code>has_many :jobs</code> <code>has_many :roles, through: :jobs</code></p>
  
  <p>Also, how should I be authenticating these roles? I'm currently doing this in a before block in my controllers:</p>
  
  <pre><code>def only_superadmins
      redirect_to root_url if !current_user.has_role?('superadmin')
  end
  </code></pre>
  
  <p>I also have a bunch of these methods in my application controller, <code>only_superadmins</code>, <code>only_cyclists</code> ect and I call them via the <code>before_method</code> method in various sub-controllers. </p>
  
  <p>Is this okay? Should I be using cancan or something? </p>
  
  <p>If I am doing it right, I'm wondering how I should dynamically create these methods with my Gem. I'm thinking something along these lines:</p>
  
  <pre><code>class panel_controller &lt; ApplicationController   
      allowed_roles [:super_admin, :forum_admin, :store_admin]
  end
  </code></pre>
  
  <p>and the allowed_roles method would create these methods</p>
  
  <pre><code>def allowed_roles(role_array)
      role_array.each do |role|
           define "only_#{role.to_s}s" do |arg|
              redirect_to root_url if !current_user.has_role?(arg.to_s)
           end
      end
  end
  </code></pre>
  
  <p>So that would programatically create these methods:</p>
  
  <pre><code>def only_super_admins
      redirect_to root_url if !current_user.has_role?('super_admin')
  end
  
  def only_forum_admins
      redirect_to root_url if !current_user.has_role?('forum_admin')
  end
  
  
  def only_store_admins
      redirect_to root_url if !current_user.has_role?('store_admin')
  end
  </code></pre>
  
  <p>While I don't see why that wouldn't work, that doesn't strike me as too efficient.</p>
  
  <p>Maybe <code>allowed_roles</code> should look like this:</p>
  
  <pre><code>def allowed_roles(wanted_roles)
      redirect_to root_url unless (current_user.role_array &amp; wanted_roles).empty? # it's ONLY empty when any of the current_user roles exists in the wanted_roles array
  end
  </code></pre>
  
  <p>I just want some pointers really :)</p>
  
  <p><strong>How do I create a gem to make the <code>allowed_roles</code> method available to the controllers and <code>multiroles</code> available to the user model?</strong></p>
  
  <p>Can <code>cancan</code> manage multiple roles like this? Should I just be using that?</p>