Pundit: una gema Rails de gestión de usuarios

En cualquier sistema web siempre es necesario tener claro la gestión de usuarios, en rails es muy conocida la gema CanCanCan es bastante intuitiva y de fácil implementación pero cuando la administración de permisos es más compleja ¿Cómo lo hacemos? es cuando descubrí la gema Pundit la cual trabaja bajo políticas para cada controlador dentro del sistema, entonces podemos definir los permisos para el método que queramos.

Ejemplo práctico

Lo primero es agregar la gema al gemfile del proyecto:

gem "pundit"  

Ejecutamos bundle install, luego incluimos Pundit en application_controller.rb:

    class ApplicationController < ActionController::Base
        include Pundit
        protect_from_forgery
    end

Asignamos roles en el modelo de usuarios, en este caso utilizaremos:

    enum role: [:user, :vip, :admin]
    after_initialize :set_default_role, :if => :new_record?
      def set_default_role
          self.role ||= :user
      end

Para definir los permisos según rol y acción Pundit lo hace a través de politicas las cuales podemos generar en primera instancia con:

rails g pundit:install

Luego de esto se crea una política para application_controller.rb en app/policies/ la cual podemos heredar y no necesitamos redefir. En esta carpeta es donde crearemos políticas para cada uno de los controladores que necesitemos. Por ejemplo si tenemos el controlador post una posible política sería:

    class PostPolicy
        attr_reader :user, :post

         def initialize(user, post)
            @user = user
            @post = post
         end

        def update?
            if user.admin?
                true
            else
                false
            end
        end
    end

donde "user" será proporcionado por devise y "post" desde el controlador en donde se utilizará la política. Para poner en uso la política en el controlador usamos:

    def update
      authorize @post
      respond_to do |format|
          ...
      end
    end

De esta forma se puede definir el acceso a cualquier método dentro del controlador, también se pueden ocultar links utilizando:

    <% if policy(:post).show? %>
        <%= link_to 'Posts', posts_path %>
    <% end %>

Con esto solo basta agregar show al archivo de políticas de Post.

Documentación oficial de Pundit

Con esta introducción y ejemplo ya se puede empezar a utilizar Pundit. Para profundizar más en la gema visita la documentación oficial en Gitub.