amos-kibet

amos-kibet

I have a FilterCheck policy that looks like this:

use Ash.Policy.FilterCheck

 def filter(actor, context, options) do
    tenant_id = context.subject.tenant.id

    resource_name =
      options[:resource]
      |> to_string()
      |> String.split(".")
      |> List.last()

    expr(
      exists(
        MyApp.AccessRight,
        tenant_id == ^tenant_id and
          resource_name == ^resource_name and read == true)
      )
    )

    # dbg()
  end

and I use this policy in my resource this way:

  policies do
    policy action(:list_paginated) do
      authorize_if MyFilterCheckPolicy
    end
  end

and here is how I use the resource action in my LiveView:

Posts.list_paginated(actor: current_user, tenant: tenant)

The problem:
For some reason, this setup does not work; it raises this error:

[error] ** (ArgumentError) `nil` is not a Spark DSL module.

    nil.persisted(:data_layer)
    (spark 2.2.31) lib/spark/dsl/extension.ex:138: Spark.Dsl.Extension.persisted!/3
    (ash 3.4.21) lib/ash/filter/filter.ex:3734: Ash.Filter.do_hydrate_refs/2
    ... more stacktraces below

and interestingly, it works if I uncomment the dbg() call at the end of the policy (see code above).

How can I fix the above error?

Showing Posts 1 to 6

zachdaniel

zachdaniel

Creator of Ash

exists does not take a resource it takes a relationship or relationship oath.

i.e exists(access_rights, ....

or

exists(access_rights.user, ...

Please open an issue describing that bad error output and I will look to make it clearer.

almirsarajcic

almirsarajcic

Thanks for the response.

I’m working together with Amos on this, so I just want to provide more context.

The reason why we put the module name there was we tried to use the tenant relationship, instead of relationship to the record policy is affecting. We’re trying to use the same policy for several types of resources that don’t have direct relationship to access_rights.

Is it possible to get the tenant from the context, and then get access_rights rows associated with it plus filter based on some additional conditions?

I’ve tried this but it didn’t work.

def filter(actor, context, options) do
  tenant =
    case context.query.tenant do
      %Tenant{} = tenant ->
        tenant

      _ ->
        tenant_id = String.replace(context.query.tenant, "tenant_", "")
        Ash.get!(Tenant, tenant_id)
    end

  resource_name =
    options[:resource]
    |> to_string()
    |> String.split(".")
    |> List.last()

  expr(
    exists(
      ^tenant.access_rights,
      resource_name == ^resource_name and
        read == true and
        exists(group.group_users, user_id == ^actor.id)
    )
  )
end
zachdaniel

zachdaniel

Creator of Ash

:thinking: You should be able to do something along those lines, yes. When you say it didn’t work, what do you mean?

almirsarajcic

almirsarajcic

I’ve had the same error.

I’ll try two things: manual relationships vs using lower-level Ash.Query functions and post the result.

zachdaniel

zachdaniel

Creator of Ash

Ah, sorry I just looked more closely. You can’t use exists with anything other than a relationship reference. ^value is not a relationship reference.

Here is the related issue for the improvement we’d like to make. Support resources as aggregate targets in expressions · Issue #939 · ash-project/ash · GitHub

So to do this logic that you want you’ll need to do the work entirely in the check module. and return {:ok, true | false}

almirsarajcic

almirsarajcic

Since I needed to do a filter check instead of a simple check, I ended up with a manual relationship and with more knowledge about the powers of Ash. Mind getting blown every day… :exploding_head:

Thanks!

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews