Hello, friends!
So on the website documentation, we have an example of a simple policy check:
# we're inside of a module here
def match?(%MyApp.User{age: age} = _actor, %{resource: MyApp.Beer} = _context, _opts) do
age >= 21
end
All well and good, but in a more real world example we’d probably have:
- Roles for Users
- Many permissions for those roles
- Potentially many permissions for users
So let’s say we have something like the following:
A User resource:
defmodule MyApp.Accounts.User do
@moduledoc """
Close to a real world example of a basic users, but
obviously there's a lot more stuff here.
Shortened for the sake of brevity.
"""
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [AshAuthentication]
postgres do
table "app_users"
repo MyApp.Repo
end
attributes do
uuid_primary_key :id
attribute :first_name, :ci_string, allow_nil?: false
attribute :last_name, :ci_string, allow_nil?: false
attribute :email, :ci_string, allow_nil?: false, sensitive?: true
attribute :hashed_password, :string, allow_nil?: false, sensitive?: true
create_timestamp(:created_at)
update_timestamp(:updated_at)
end
relationships do
has_one :role, MyApp.Accounts.Role
many_to_many :permissions, MyApp.Accounts.User do
through MyApp.Accounts.UserPermission
source_attribute_on_join_resource :user_id
destination_attribute_on_join_resource :permission_id
end
end
And of course…
A Role resource:
defmodule MyApp.Accounts.Role do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "roles"
repo MyApp.Repo
end
attributes do
uuid_primary_key :id
attribute :name, :string do
allow_nil? false
end
attribute :description, :string do
allow_nil? false
end
end
relationships do
has_many :users, MyApp.Accounts.User
many_to_many :permissions, MyApp.Accounts.Role do
through MyApp.Accounts.RolePermission
source_attribute_on_join_resource :role_id
destination_attribute_on_join_resource :permission_id
end
end
end
A Permission resource:
defmodule MyApp.Accounts.Permission do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "permissiones"
repo MyApp.Repo
end
attributes do
uuid_primary_key :id
attribute :name, :string do
allow_nil? false
end
attribute :description, :string do
allow_nil? false
end
end
relationships do
many_to_many :roles, MyApp.Accounts.Permission do
through MyApp.Accounts.RolePermission
source_attribute_on_join_resource :permission_id
destination_attribute_on_join_resource :role_id
end
many_to_many :users, MyApp.Accounts.Permission do
through MyApp.Accounts.UserPermission
source_attribute_on_join_resource :permission_id
destination_attribute_on_join_resource :user_id
end
end
end
A RolePermission resource:
defmodule MyApp.Accounts.RolePermission do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "role_permissions"
repo MyApp.Repo
end
relationships do
belongs_to :role, MyApp.Accounts.Role do
primary_key? true
allow_nil? false
end
belongs_to :permission, MyApp.Accounts.Permission do
primary_key? true
allow_nil? false
end
end
end
A UserPermission resource:
defmodule MyApp.Accounts.UserPermission do
use Ash.Resource,
data_layer: AshPostgres.DataLayer
postgres do
table "user_permissions"
repo MyApp.Repo
end
relationships do
belongs_to :user, MyApp.Accounts.User do
primary_key? true
allow_nil? false
end
belongs_to :permission, MyApp.Accounts.Permission do
primary_key? true
allow_nil? false
end
end
end
And you want to check both the role and user permissions.
My question would be how do we go about doing the simple policy checks when we have a role-permission setup like this? Because the check itself isn’t complex, it’s more of a “how do we get there” question.






















