Seeking clarification about value_is_key option in manage_relationship

defmodule Resources.Follow do
  relationships do
    belongs_to :follower, User, attribute_type: :integer
    belongs_to :followee, User, attribute_type: :integer
  end

  actions do
    create :create_with_username do
      argument :username, :ci_string, allow_nil?: false
      change manage_relationship(:username, :followee, value_is_key: :username, use_identities: [:uniq_username])
    end
  end
end

In Follow resource, there are two foreign keys follower_id, followee_id.
They are integers.
But I want to find user with username and relate it with
change manage_relationship(:username, :followee, value_is_key: :username, use_identities: [:uniq_username])
this code.

Is it possible to

  1. find by username and
  2. relate with id?

using manage_relationship?

The value_is_key option basically makes the value in your map act as the key for managing relationships. When you set it to true, it means the map’s value is used as the key, which is great if the value itself is something important or unique. If there’s a particular scenario of if something’s still unclear, just share a bit more info, and it’ll be sorted out.

  actions do
    defaults [:read, :destroy, create: :*, update: :*]

    create :create_by_username do
      argument :username, :ci_string, allow_nil?: false
      change relate_actor(:user)

      change manage_relationship(:username, :bookmarked_user,
               type: :append,
               value_is_key: :username,
               use_identities: [:uniq_username]
             )
    end

    create :create_by_map do
      argument :map, :map, allow_nil?: false
      change relate_actor(:user)

      change manage_relationship(:map, :bookmarked_user,
               type: :append,
               value_is_key: :username,
               use_identities: [:uniq_username]
             )
    end
  end

Wow… Is this what you mean?
First one doesn’t work, but second one works.

@zachdaniel
Why does the first action create_by_username doesn’t work, but second action create_by_map work?
I think first action and second action pass same amount of information to manage_relationship.

What value_is_key does is rewrite each value given to manage_relationship, to be a map with a single key (the value_is_key option) and a value of the original value. For example:

# in create_by_username

#action input

%{
  username:  "foo"
}

# what gets passed into `manage_relationship`

%{username: "foo"}

# we take the value `"foo"`, and put it in a map with the key `username`

Contrast that with create_by_map, which may make it more clear why create_by_map doesn’t work:

# in create_by_map


# action_input

%{
  map: %{id: 10} # or %{username: "username"}
}

# what gets passed into `manage_relationship`

%{
  username: %{id: 10} # or %{username: "username"}
}

# we take the value `%{id: 10}`, and put it in a map with the key `username`

Naturally, username: %{id: 10} is not what you want.

Hmm… Interesting.

  1. Follow.create_by_username doesn’t work, actually.
  2. I passed %{username: "zach"} to create_by_map and it works.
    The full code is Follow.create_by_map!(%{map: %{username: "zach"}, actor: user)

I think this could be a bug, after reading your comment.
If you also think this is a bug, I’ll post a failing test to github ash repo tomorrow.

I’d have to see what you are passing to Follow.create_by_username. Follow.create_by_map! does work if you pass it in the way you are passing it. But I’m assuming what you want is something like Follow.create_by_username("zach").

So in what way is it not working?

I implemented this using the alembic/realworld fork.
In my private repository, the “follow_by_username” test fails, but it doesn’t fail in this example.
I need to figure out what I missed.

Sorry for any confusion.

Are you getting an error message of some kind? What happens when it “doesn’t work”?


I got this error, but I think not that helpful.

The implication of that error is that there is no user with the username "oma.beier". Could that be the case?

No. I executed the action right after creating "oma.beier".
So it coudn’t be possible.

Now I know it’s my fault, so I should debug my code more. Thanks for your help.

Do you perhaps have policies on the user that could be filtering the read?

Nope.

    policy action_type(:read) do
      authorize_if always()
    end

This is the user read action policy.

And sorry for wasting your time.
I can’t now reproduce it in my private repo anymore.
It works like magic.