Authorization Context
So far, our policies have been simple because we haven’t had real users. Let’s add authentication and learn about authorization context.
What is Authorization Context?
Authorization context is the information available to your policy when making authorization decisions. By default, Action Policy provides:
user- The current user (fromcurrent_user)record- The object being authorized
You can add additional context like account, organization, or tenant.
Setting Up Authentication
First, let’s generate Rails authentication:
$ bin/rails generate authenticationThis creates:
Usermodel with email and passwordSessionmodel for tracking sessionsSessionsControllerfor login/logoutAuthenticationconcern for controllers
Now migrate the database:
$ bin/rails db:migrateUnderstanding the Generated Code
Open :
module Authentication extend ActiveSupport::Concern
included do before_action :require_authentication helper_method :authenticated? end
# ...
private def authenticated? Current.session.present? end
def require_authentication resume_session || request_authentication endendThe key method here is Current.session which gives us access to the current user.
Configuring Action Policy Context
Open and update it:
class ApplicationController < ActionController::Base include Authentication
# Action Policy will use Current.user as the authorization context authorize :user, through: -> { Current.user }
verify_authorized
rescue_from ActionPolicy::Unauthorized do |exception| redirect_to root_path, alert: "You are not authorized to perform this action." endendThe authorize :user, through: line tells Action Policy how to get the current user.
Create a Test User
Let’s create a user to test with. Run the Rails console:
$ bin/rails consolestore(dev)> User.create!(email_address: "admin@example.com", password: "secret123")=> #<User id: 1, email_address: "admin@example.com", ...>Update the Policy
Now let’s update our ProductPolicy to use the user:
# frozen_string_literal: true
class ProductPolicy < ApplicationPolicy def index? true # Anyone can view the list end
def show? true # Anyone can view a product end
def create? user.present? # Only logged-in users can create end
def update? user.present? # Only logged-in users can update end
def destroy? user.present? # Only logged-in users can delete endendSkip Authentication for Public Pages
We need to allow viewing products without being logged in. Update ProductsController:
class ProductsController < ApplicationController skip_before_action :require_authentication, only: [:index, :show] before_action :set_product, only: %i[ show edit update destroy ]
# ... rest of controllerendHandling Missing User
When a user isn’t logged in, Current.user is nil. Our policy needs to handle this:
def create? user.present? # Returns false if user is nilendTest It Out
Try these scenarios:
- Visit the products page as a guest - you can view products
- Try to create a product - you’ll be redirected to login
- Log in and try again - now you can create products!
Next, we’ll learn about rule aliases to reduce duplication in our policies.
- Preparing Ruby runtime
- Prepare development database
- Starting Rails server