binarypaladin

binarypaladin

So, in my quest to convert an existing system (slowly) over to Ash, I’m trying to figure out how to replicate certain patterns in the system.

For reading a single resource or updating, the Ash flow is pretty obvious with authorization. The resource is in the context and I can do whatever. Awesome.

I’m not seeing a clear example of how to handle “collection” operations.

(And by the way, now that I’m really digging in, it’s all kind of overwhelming! In good and bad ways, lol. It’s much easier to build something to learn it, which is what’s up right now.)

For instance, creating a resource. In my existing system, most of our collection type functions look like this:

defmodule Comments
  def create(context_resource, attrs, actor, opts \\ []) do
    ...
  end

  def query(context_resource, query_params, actor, opts \\ []) do
    ...
  end
end

If I’m going to create a comment, I’m likely going to want to authorize create in relation to the article. “Does this article allow comments? Is the user a real user?” This also goes really well with REST APIs that actually make use of the URL.

POST /articles/:id/comments

“Create a comment where the context is the article.”

My code is going use something in Ecto like put_assoc/3, in many cases, to attach the context to the newly created resource. The changset functions also typically take the same form: create_changeset(context_resource, attrs, user, opts \\ []). I have to imagine, thinking about your own JSON:API support, that there’s definitely a path for this, even where the implementation is different.

Queries work similarly. In the system I’m working on, I rarely deal with a collection of things in context to a user (and when I do, I pass in the user as the context resource and maybe a different one as the actor). It’s usually some children of a thing that the user has access to. So in an API example:

GET /articles/:id/comments

“I want all the comments for a blog.” Where does that play out in actions? (I probably won’t dive into relationships until I get policies working a bit better, so maybe I am ahead of myself.) I want to authorize against the article and then get the appropriate comments.

Consider this example from the docs. In this create, the only context I have is the concept of a beer. What if I wanted to create a beer in context of being in France versus the US in terms of determining the drinking age? What’s the “proper” way to provide that to the action?

I know this is long. I sense a combination of relationships and your own context stuff is how this goes together.

Also, I got hung up in authorization, lol. The answer might be, “Bruh, just go read up in on relationships.” That’s probably not on the menu till Saturday.

Showing Posts 1 to 8

zachdaniel

zachdaniel

Creator of Ash

So you have two options here.

Use the arguments to look up related info

The first one is to use the input arguments to determine the related thing, and then operate on that information.

For example:

defmodule YourApp.Checks.MatchesDrinkingAge do
  use Ash.Policy.SimpleCheck

  def match?(actor, %{source: %Ash.Changeset{} = changeset}, _opts) do
     country_id = Ash.Changeset.get_argument(changeset, :country_id)
     # lookup the country id, and return `true` or `false` depending
  end
end

Put the action on the thing that controls the rules

This is probably not what you want in this case, but can be useful to simplify

# on Country
create :add_beer do
  # create the beer in a hook
  ...
end

It’s actually a little bit inconvenient to authorize data creation when compared with our other check types, and I would really like to build up some more tools for this kind of thing.
But, although slightly more verbose than we’d prefer, you can ultimately do “anything you want” in simple checks, and those should allow for any authorization logic you need in this case.

binarypaladin

binarypaladin OP

Actually, this is fine.

I’m sorta learning that, at least for mutations, the changeset in Ash is “all the things.” It’s all the changes, hooks, and other “stuff.” Context is there. Arguments are there. I haven’t messed with with notifications yet, but… I presume they link in there too. Map.from_struct/1 has been super enlightening.

This is enough to mess with for now. Thanks!

binarypaladin

binarypaladin OP

I was thinking about starting a new topic, but this one has a lot of the context.

For creates, I just pass in %{context: %{resource: <probably-a-belongs-to-resource>}}

This works as I wanted. (I’ll have to see precisely how this plays out with APIs, but that’s not today’s problem.)

As per our Discord conversation, I was able to make an excellent filter check that can dip into related access lists on a resource. This works great for reads and updates.

I blindly tossed the check onto a create action though and was greeted with the following error:

     ** (Ash.Error.Forbidden) 
     Bread Crumbs:
       > Exception raised in: MyApp.Resource.create

     Forbidden Error

     * Cannot use a filter to authorize a create.

The actual error message is quite informative and also, duh!

Okay, fine. What I want to do is effectively run the filter query on the related resource. “Do I have management permission to the context resource?” Is there some way to utilize the filter check against the context resource inside the check?

I have a kinda crappy hack around this right now but… I’m trying to find a way to just use the check inside another check or move the expression in the check into some shared space. (It’s hard to understand, at my current state what expr/1 is applied to or how. I haven’t dug into that yet.)

binarypaladin

binarypaladin OP

And I guess on that note… the pattern I am looking for here is, “If I have permission to do X on Y resource, I should pass this check.”

I’m not really sure how to go about doing this. I can say this is precisely how my existing system works.

“Oh, you want to delete this comment? Are you the owner (check one), no? Okay, are you someone who can update the article (check two)?”

binarypaladin

binarypaladin OP

@zachdaniel I probably should have replied to you instead of the topic. (I felt like this overkill for the Discord channel.)

zachdaniel

zachdaniel

Creator of Ash

We don’t currently have a check like that, doing it would likely require some moderately difficult code. You could consolidate the logic reasonably well with custom checks and calculations etc. please open an issue to track the concept of delegating permission checks. We may have one already though, so do a search before hand if possible :slight_smile:

alexslade

alexslade

@binarypaladin @zachdaniel Did this ever make it to an issue? (I can’t find one on /ash). We’re also looking to use this pattern.

zachdaniel

zachdaniel

Creator of Ash

I don’t think so. It may be under the term “delegate” or “delegation” as an issue, not sure.

Separately: you can accomplish this for related data using calculations, just not during create actions.

https://www.answeroverflow.com/m/1398298115617849396

— All posts loaded —

Where Next? Top

Trending in Questions Top

Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
matt-savvy
Anyone here using Honeybadger? My Honeybadger account is being overwhelmed with noise from some bots. Seeing a lot of Bandit.HTTPError...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New

Other Trending Topics Top

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
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews