`relate_actor allow_nil? false` returning 400 error when `authorize_if actor_present()`

Hi friends, I have a question about change relate_actor. see my code, when i use default relate_actor which is allow_nil?: false, i get 400 error when i do not send user token or actor, for example without auth i send request
create :create do
description "Follows a blogger"
primary? true
upsert? true
upsert_identity :unique_follower_blogger

change relate_actor(:follower_user)

change fn changeset, _context ->
Ash.Changeset.force_change_attribute(changeset, :followed_at, DateTime.utc_now())
end
end
create :create do
description "Follows a blogger"
primary? true
upsert? true
upsert_identity :unique_follower_blogger

change relate_actor(:follower_user)

change fn changeset, _context ->
Ash.Changeset.force_change_attribute(changeset, :followed_at, DateTime.utc_now())
end
end
But with these policies i expected to return 403 error
policies do
bypass action(:by_blogger) do
authorize_if always()
end

bypass action(:create) do
authorize_if actor_present()
end

policy action([:read, :toggle_notifications, :unfollow]) do
authorize_if expr(follower_user_id == ^actor(:id))
end
end
policies do
bypass action(:by_blogger) do
authorize_if always()
end

bypass action(:create) do
authorize_if actor_present()
end

policy action([:read, :toggle_notifications, :unfollow]) do
authorize_if expr(follower_user_id == ^actor(:id))
end
end
So i am force to use change relate_actor(:follower_user, allow_nil?: true) , with allow_nil?: true it returns forbidden error instead of 400. Why it has this behaviour? am i forgetting the policy concept again 😱 Thank you in advance
7 Replies
ZachDaniel
ZachDaniel2mo ago
change relate_actor(:actor, allow_nil?: true) IIRC
Shahryar
ShahryarOP2mo ago
yes i did and it works! but is there any reason? AI says:
The issue is that relate_actor is checking for the actor in the context, not checking the data being created.
ZachDaniel
ZachDaniel2mo ago
relate_actor relates the current user to the record being created/updated
Shahryar
ShahryarOP2mo ago
Sorry to waste your time, I am confused and still do not understand why the policy let it go to change and do not return error immediately!! when authorize_if actor_present() not passed i just read this code too https://github.com/ash-project/ash/blob/6d21033ec799f7ebce0c9e8b36beb1583e77b63b/lib/ash/resource/change/relate_actor.ex#L55-L66
bypass action(:create) do
authorize_if actor_present()
end
bypass action(:create) do
authorize_if actor_present()
end
ZachDaniel
ZachDaniel2mo ago
Changes are run before policies But not the books added by the changes
Shahryar
ShahryarOP2mo ago
This Discord has not any option to bookmark or pin it 🥲 , it is very important . i think it is not in policy doc https://hexdocs.pm/ash/policies.html Thank you Sorry again 🙏 , i think filter expr in like changes run before policies in read? like this return 400
read :by_user do
description "Reads all bloggers followed by the current user with pagination"
filter expr(follower_user_id == ^actor(:id))
pagination offset?: true, default_limit: 20, max_page_size: 100, countable: true
end
read :by_user do
description "Reads all bloggers followed by the current user with pagination"
filter expr(follower_user_id == ^actor(:id))
pagination offset?: true, default_limit: 20, max_page_size: 100, countable: true
end
is there better and short way to get 403 instead of this code?
read :by_user do
description "Reads all bloggers followed by the current user with pagination"

prepare fn query, context ->
if actor = context.actor do
Ash.Query.filter(query, follower_user_id == ^actor.id)
else
query
end
end

pagination offset?: true, default_limit: 20, max_page_size: 100, countable: true
end
read :by_user do
description "Reads all bloggers followed by the current user with pagination"

prepare fn query, context ->
if actor = context.actor do
Ash.Query.filter(query, follower_user_id == ^actor.id)
else
query
end
end

pagination offset?: true, default_limit: 20, max_page_size: 100, countable: true
end
ZachDaniel
ZachDaniel2mo ago
Ah...that's interesting. No that is the only way. Although your second clause there should be filter(false)

Did you find this page helpful?