Using authorize!
Now that we have a policy, let’s use it in our controller. The authorize! method is the primary way to enforce authorization.
How authorize! Works
When you call authorize!, Action Policy:
- Finds the policy class -
Product->ProductPolicy - Infers the rule -
showaction ->show?rule - Gets the user - Uses
current_userby default - Checks the rule - Calls
ProductPolicy#show? - Raises on failure - Throws
ActionPolicy::Unauthorizedif the rule returnsfalse
Add Authorization to the Controller
Open and add authorize! calls:
class ProductsController < ApplicationController before_action :set_product, only: %i[ show edit update destroy ]
def index @products = Product.all authorize! @products end
def show authorize! @product end
# ... rest of the controllerendHandling Authorization Failures
When authorization fails, Action Policy raises ActionPolicy::Unauthorized. Let’s add a global handler in ApplicationController:
Open and add:
class ApplicationController < ActionController::Base rescue_from ActionPolicy::Unauthorized do |exception| redirect_to root_path, alert: "You are not authorized to perform this action." endendTest the Authorization
Adding More Rules
Now let’s add rules for the other actions. Update :
# frozen_string_literal: true
class ProductPolicy < ApplicationPolicy def index? true end
def show? true end
def new? # For now, allow everyone true end
def create? true end
def update? true end
def destroy? true endendUpdate the Controller
Add authorize! to all actions:
class ProductsController < ApplicationController before_action :set_product, only: %i[ show edit update destroy ]
def index @products = Product.all authorize! @products end
def show authorize! @product end
def new @product = Product.new authorize! @product end
def create @product = Product.new(product_params) authorize! @product if @product.save redirect_to @product else render :new, status: :unprocessable_entity end end
def edit authorize! @product end
def update authorize! @product if @product.update(product_params) redirect_to @product else render :edit, status: :unprocessable_entity end end
def destroy authorize! @product @product.destroy redirect_to products_path end
private def set_product @product = Product.find(params[:id]) end
def product_params params.expect(product: [ :name ]) endendExplicit Rule Specification
Sometimes you want to use a different rule than the action name:
# Use update? rule instead of edit?authorize! @product, to: :update?
# Use a specific policy classauthorize! @product, with: SpecialProductPolicyGreat! Now our controller is protected by authorization. Next, let’s learn how to check permissions in views.
Files
Preparing Environment
- Preparing Ruby runtime
- Prepare development database
- Starting Rails server