Skip to main content
Version: v2.0

Creating a custom role

This tutorial will walk you through adding a custom author role to your application.

Prerequisites

Ensure you have completed the Organization and Roles Tutorial

Data model

The data model for this tutorial is the same as the Organization and Roles Tutorial

Generate a new policy

rails generate rhino:policy Author
info

rails generate is a built in Rails command that will run a generator for you. In this case we are generating a new policy called "author". There are a number of generators available in Rails & Rhino. You can see a list of them by running rails generate without any arguments.

There will now be a new files, app/policies/author_policy.rb with the skeleton of a policy and test/policies/author_policy_test.rb with the skeleton of a policy test.

Edit the policy

app/policies/author_policy.rb
class AuthorPolicy < ::Rhino::ViewerPolicy
def check_author
return false unless auth_owner

# Check if the user is the author of the blog
record.class.where(id: record.id).joins(record.joins_for(:blog)).exists?("blogs.user_id": auth_owner.id)
end

# Can always create (for themselves)
def create?
authorize_action(true)
end

# Can only update if they are the author
def update?
authorize_action(check_author)
end

# Can only destroy if they are the author
def destroy?
authorize_action(check_author)
end

class Scope < ::Rhino::ViewerPolicy::Scope
end
end

Seed the database

Create an additional organization and role for testing.

db/seeds.rb
# Function to generate sample blogs and blog posts
def generate_blogs(user, org)
5.times do
blog = Blog.create!(user_id: user.id, organization: org, title: FFaker::Book.unique.author, category_id: Category.ids.sample)
20.times do
BlogPost.create!(blog_id: blog.id, title: FFaker::Book.unique.title, body: FFaker::Book.unique.description, published: [true, false].sample)
end
end
end

AdminUser.find_or_create_by(email: "admin@example.com") do |u|
u.password = "password"
end

# Create two sample users
user = User.find_or_create_by(email: "test@example.com") do |u|
u.password = "password"
u.confirmed_at = DateTime.now
end
user_other = User.find_or_create_by(email: "other@example.com") do |u|
u.password = "password"
u.confirmed_at = DateTime.now
end

# Create sample organizations
-org = ["Single User Org", "Multi User Org", "Viewer Org", "Editor Org"].map do |name|
+org = ["Single User Org", "Multi User Org", "Viewer Org", "Editor Org", "Author Org"].map do |name|
Organization.create!(name:)
end

role_admin = Role.create!(name: "admin")
role_viewer = Role.create!(name: "viewer")
role_editor = Role.create!(name: "editor")
+role_author = Role.create!(name: "author")

# The test@example.com user is the only user and admin of the "Single User Org" organization
UsersRole.create!(user: user, organization: org[0], role: role_admin)
# Only test@example.com authors blogs in the "MuSinglelti User Org" organization
generate_blogs(user, org[0])

# The test@example.com and other@example.com are both users and admins of the "Multi User Org" organization
UsersRole.create!(user: user, organization: org[1], role: role_admin)
# Both users author blogs in the "Multi User Org" organization
generate_blogs(user, org[1])
generate_blogs(user_other, org[1])

# The test@example.com is a viewer and other@example.com is an admin of the "Viewer Org" organization
UsersRole.create!(user: user, organization: org[2], role: role_viewer)
UsersRole.create!(user: user_other, organization: org[2], role: role_admin)
# Only other@example.com authors blogs in the "Viewer Org" organization
generate_blogs(user_other, org[3])

# The test@example.com is an editor and other@example.com is an admin of the "Editor Org" organization
UsersRole.create!(user: user, organization: org[3], role: role_editor)
UsersRole.create!(user: user_other, organization: org[3], role: role_admin)
# Only other@example.com authors blogs in the "Editor Org" organization
generate_blogs(user_other, org[3])

+# The test@example.com is an author and other@example.com is an admin of the "Author Org" organization
+UsersRole.create!(user: user, organization: org[4], role: role_author)
+UsersRole.create!(user: user_other, organization: org[4], role: role_admin)
+# Only other@example.com authors blogs in the "Editor Org" organization
+generate_blogs(user, org[4])
+generate_blogs(user_other, org[4])

And add the seed data to the database

rails db:seed

Restart the server

rails s

Try the Author Org

Login to the application with test@example.com and password and switch to the "Author Org" organization. Viewing the blogs where the author is test@example.com will allow editing and deleting:

While blogs where the author is not test@example.com will not: