Best practice: Manual Relationship or Action?

In my application, I have a common pattern where there is some global resource that all users have access to but then each user has their own data associated with it:

A Question and its Answers are global, but the user has their own UserAnswer to the question.

So, with exception of some kind of reporting or analytics the data will be accessed from the context of a user wanting to see their own data.

Here’s my question, what’s the best practice for accessing data from a user’s context?

Should I have manual relationships that make an interface so that Question has_one UserAnswer?

Or should I have an action that is something like UserAnswer.get_for_answer()

Or does it matter? Is it just a different interface to the same thing and it’s personal preference?

I would suggest that it is mostly personal preference, unless you want to support requests to an API that will return it all in one pass, in which case relationships or calculations is the way to go. With that said, you can actually do some things to avoid needing manual relationships in general. For example:

relationships do
  has_one :user_answer, UserAnswer do
    read_action :for_actor

# on UserAnswer

read :for_actor do
  filter expr(user_id == ^actor(:id))
1 Like

In addition to Zach’s answer I was also thinking that this might be something you would approach with an Ash Policy, where the user/actor can only see their own answers.

So you could have something like the following in the UserAnswer resource:

policies do
  bypass actor_attribute_equals(:super_user, true) do
    authorize_if always()

  policy action_type(:read) do
    # if the actor is related to the UserAnswer via that data's `user` relationship, authorize
    authorize_if relates_to_actor_via(:user)
1 Like

Yes, that will also work :slight_smile:

Thanks guys, super helpful

I think this is the route I will take, I need to add authorization/learn about policies anyway. This is really nice, thanks for pointing it out.