Portier
Portier is an gem that manage permissions in a rails project. The permission rules are flexible, non-obstrusive, scalable and can be applied to the controller actions, and views.
Install
In your Gemfile:
gem 'portier'
Authorizing the controller requests
Bootstrap Portier
In order to let portier control the requests to your application, you need to add the before_filter below in your application_controller.rb. You also need to define a current_user method
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
# This filter the requests using the permission files
before_action :protect_app
# You can define the current_user anyway you want as long as it return the current user record.
def current_user
# This is only an example of current_user method. Feel free to do it the way you want.
begin
@current_user ||= User.find session[:current_user]
rescue
@current_user = nil
end
end
...
The Permission Files
Once this is done, every controller will have to be match with a permission file. So, for the products_controller.rb
you'll have to create the file app/permissions/products_permission.rb
.
Describing a permission file
The permission file will define the access rules to every action called on the controller.
# app/permissions/products_permission.rb
class ProductsPermission < Portier::ApplicationPermission
# User will have access to any undescribed actions
def default
true
end
# The access will only granted if the product is available.
# product is provided by ApplicationPermission.
# product return the current product record
def show
product.available?
end
# You can set a custom error message with the method set_access_denied_message.
# This message will be available in the controllers and views throught the
# method access_denied_message. If it's not set, this method will return nil.
# set_access_denied_message always return false.
def create
if not current_user
set_access_denied_message "You need to log in to create this product."
elsif not current_user.can_create_product?
set_access_denied_message "You don't have the right to create product."
else
true
end
end
# The access to the edit/update actions will only be available
# if the current user is and Administrator
# The current_user method must be defined in your ApplicationController
def modify
current_user and current_user.admin?
end
# Revoke access to the destroy action.
def destroy
false
end
end
# consult = index and show
# add = new and create
# modify = edit and update
# Define the parameters that can be sent by the user.
# In your products_controller, you can call the method permitted_params.
# This method will be the equivalent of :
# params.require(:product).permit(:picture, :name, :description)
def permitted_params
if current_user and current_user.employe?
[:picture, :name, :description]
elsif current_user and current_user.admin?
[:picture, :name, :description, :price]
else
[]
end
end
The View Tags
In order to filter content in the views, you can add tags in the special view_tags_permission.rb.
# app/permissions/view_tags_permission.rb
class ViewTagsPermission < Portier::ViewTagsPermission
# Only accept this tag if the user is an administrator
def show_the_admin_link
current_user.admin?
end
end
In your views, you can then use the can_view? method to filter content.
<%# app/views/products/show.html.erb %>
<%= link_to 'Admin', admin_path if can_view? :show_the_admin_link %>
can?
In your views, you can also use the method can?
to filter content.
<%# app/views/products/show.html.erb %>
<%= link_to 'Edit product', edit_product_path(id: @product.id) if can? :edit, @product %>
Both can?
and can_view?
methods can take options
<%# app/views/products/show.html.erb %>
<%= link_to 'Admin', admin_path if can_view? :show_the_admin_link, special: true %>
# app/permissions/view_tags_permission.rb
class ViewTagsPermission < Portier::ViewTagsPermission
# Only accept this tag if the user is a special administrator
def show_the_admin_link
current_user.admin? and options[:special]
end
end
namespace
If you are using namespacing in your controller, you can pass the namespace option.
<%# app/views/admin/products/show.html.erb %>
<%= link_to 'Edit product', edit_product_path(id: @product.id) if can? :edit, @product, namespace: :admin %>
Copyright
Copyright (c) 2014 Alchimik. See LICENSE for further details.