From 5472a400d126fbadb8b61c71ea28a204c72a3a90 Mon Sep 17 00:00:00 2001 From: sto Date: Sat, 22 Mar 2025 09:48:40 +0100 Subject: [PATCH] Install Pundit and add UserPolicy --- Gemfile | 2 + Gemfile.lock | 3 ++ app/controllers/application_controller.rb | 15 ++++++- app/controllers/users_controller.rb | 13 ++++++ app/policies/application_policy.rb | 53 +++++++++++++++++++++++ app/policies/user_policy.rb | 29 +++++++++++++ 6 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 app/policies/application_policy.rb create mode 100644 app/policies/user_policy.rb diff --git a/Gemfile b/Gemfile index fbee302..d8d3b5c 100644 --- a/Gemfile +++ b/Gemfile @@ -67,3 +67,5 @@ group :test do gem "capybara" gem "selenium-webdriver" end + +gem "pundit", "~> 2.5" diff --git a/Gemfile.lock b/Gemfile.lock index 52da423..9a05126 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -221,6 +221,8 @@ GEM public_suffix (6.0.1) puma (6.6.0) nio4r (~> 2.0) + pundit (2.5.0) + activesupport (>= 3.0.0) raabro (1.4.0) racc (1.8.1) rack (3.1.12) @@ -406,6 +408,7 @@ DEPENDENCIES kamal propshaft puma (>= 5.0) + pundit (~> 2.5) rails (~> 8.0.2) rubocop-rails-omakase selenium-webdriver diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4b26cd2..a248e7e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,8 +1,14 @@ class ApplicationController < ActionController::Base include Authentication + include Pundit::Authorization + + before_action :set_title, :set_current_user + # TODO: add later + # after_action :verify_authorized + # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has. allow_browser versions: :modern - before_action :set_title, :set_current_user + rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized layout "authenticated" private @@ -14,4 +20,11 @@ class ApplicationController < ActionController::Base def set_current_user @current_user = current_user end + + def user_not_authorized(exception) + policy_name = exception.policy.class.to_s.underscore + + flash[:error] = t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default + redirect_back_or_to(root_path) + end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index da4a368..d85b9ea 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -2,15 +2,21 @@ class UsersController < ApplicationController before_action :set_user, only: %i[ destroy edit show update ] def index + authorize :user + @title = "All users" @users = User.all end def edit + authorize @user + @title = "My settings" end def update + authorize @user + if @user.update(user_params) redirect_to contests_path else @@ -19,15 +25,21 @@ class UsersController < ApplicationController end def show + authorize @user + redirect_to edit_user_path(@user) end def new + authorize :user + @title = "New user" @user = User.new() end def create + authorize :user + @user = User.new(user_params) if @user.save redirect_to users_path @@ -38,6 +50,7 @@ class UsersController < ApplicationController end def destroy + authorize @user end private diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb new file mode 100644 index 0000000..be644fe --- /dev/null +++ b/app/policies/application_policy.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +class ApplicationPolicy + attr_reader :user, :record + + def initialize(user, record) + @user = user + @record = record + end + + def index? + false + end + + def show? + false + end + + def create? + false + end + + def new? + create? + end + + def update? + false + end + + def edit? + update? + end + + def destroy? + false + end + + class Scope + def initialize(user, scope) + @user = user + @scope = scope + end + + def resolve + raise NoMethodError, "You must define #resolve in #{self.class}" + end + + private + + attr_reader :user, :scope + end +end diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb new file mode 100644 index 0000000..3651cbe --- /dev/null +++ b/app/policies/user_policy.rb @@ -0,0 +1,29 @@ +class UserPolicy < ApplicationPolicy + def index + user.admin? + end + + def show? + user.admin? || user.id == record.id + end + + def new? + user.admin? + end + + def create? + user.admin? + end + + def edit? + user.admin? || user.id == record.id + end + + def update? + user.admin? || user.id == record.id + end + + def destroy? + user.admin? + end +end