Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Roles (Part 1) #286

Merged
merged 3 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ gem "flipper-ui"
gem "httparty", "~> 0.21"
gem "invisible_captcha"
gem "omniauth-azure-activedirectory-v2"
gem "rolify"
gem "sentry-rails", "~> 5.11"

group :test do
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ GEM
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.2.6)
rolify (6.0.1)
rspec-core (3.12.2)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.3)
Expand Down Expand Up @@ -499,6 +500,7 @@ DEPENDENCIES
pry-byebug
puma (~> 6.4)
rails (~> 7.0.8)
rolify
rspec-rails
rubocop-govuk
rubocop-performance
Expand Down
16 changes: 14 additions & 2 deletions app/controllers/system_admin/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ def index

def new
@user = User.new
@roles = Role.all
end

def edit; end
def edit
@roles = Role.all
end

def create
@user = User.new(user_params)
@user.roles = []
params[:user][:role_ids].each do |role_id|
@user.add_role(Role.find(role_id).name) if role_id.present?
end

if @user.save
redirect_to(users_path, notice: t("users.create.success"))
Expand All @@ -24,6 +31,11 @@ def create

def update
if @user.update(user_params)
@user.roles = []
params[:user][:role_ids].each do |role_id|
@user.add_role(Role.find(role_id).name) if role_id.present?
end
@user.save
redirect_to(users_path, notice: t("users.update.success"))
else
render(:edit, status: :unprocessable_entity)
Expand All @@ -45,7 +57,7 @@ def set_user

# Only allow a list of trusted parameters through.
def user_params
params.require(:user).permit(:email)
params.require(:user).permit(:email, :role_ids)
end
end
end
26 changes: 26 additions & 0 deletions app/models/role.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# == Schema Information
#
# Table name: roles
#
# id :bigint not null, primary key
# name :string
# resource_type :string
# created_at :datetime not null
# updated_at :datetime not null
# resource_id :bigint
#
class Role < ApplicationRecord
ROLES_LIST = %i[spectator servant manager admin super_admin].freeze

has_many :users, through: :users_roles

belongs_to :resource,
polymorphic: true,
optional: true

validates :resource_type,
inclusion: { in: Rolify.resource_types },
allow_nil: true

scopify
end
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
# updated_at :datetime not null
#
class User < ApplicationRecord
rolify
audited
devise :omniauthable, omniauth_providers: %i[azure_activedirectory_v2]
end
1 change: 1 addition & 0 deletions app/views/system_admin/users/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<%= f.govuk_error_summary %>

<%= f.govuk_text_field :email, label: { text: 'Email' }, hint: { text: 'The email address of the user' } %>
<%= f.govuk_collection_check_boxes :role_ids, @roles, :id, ->(r){r.name.humanize}, legend: { text: "Roles" } %>

<%= f.govuk_submit("Save") %>
<% end %>
10 changes: 10 additions & 0 deletions config/initializers/rolify.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Rolify.configure do |config|
# By default ORM adapter is ActiveRecord. uncomment to use mongoid
# config.use_mongoid

# Dynamic shortcuts for User class (user.is_admin? like methods). Default is: false
# config.use_dynamic_shortcuts

# Configuration to remove roles from database once the last resource is removed. Default is: true
# config.remove_role_if_empty = false
end
18 changes: 18 additions & 0 deletions db/migrate/20231003024901_rolify_create_roles.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class RolifyCreateRoles < ActiveRecord::Migration[7.0]
def change
create_table(:roles) do |t|
t.string :name
t.references :resource, polymorphic: true

t.timestamps
end

create_table(:users_roles, id: false) do |t|
t.references :user
t.references :role
end

add_index(:roles, %i[name resource_type resource_id])
add_index(:users_roles, %i[user_id role_id])
end
end
21 changes: 20 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions lib/tasks/roles.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace :roles do
desc "Create default roles"
task create_defaults: :environment do
Role::ROLES_LIST.each do |role_name|
Role.find_or_create_by(name: role_name)
end
end
end
16 changes: 16 additions & 0 deletions spec/factories/roles.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# == Schema Information
#
# Table name: roles
#
# id :bigint not null, primary key
# name :string
# resource_type :string
# created_at :datetime not null
# updated_at :datetime not null
# resource_id :bigint
#
FactoryBot.define do
factory :role do
name { "Admin" }
end
end
16 changes: 16 additions & 0 deletions spec/models/role_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# == Schema Information
#
# Table name: roles
#
# id :bigint not null, primary key
# name :string
# resource_type :string
# created_at :datetime not null
# updated_at :datetime not null
# resource_id :bigint
#
require "rails_helper"

RSpec.describe Role do
it { is_expected.to have_db_column(:name) }
end