I’m just not clear why this is happening, since I ensure that the type is binary_id in the migration(gist below). Any way to hint to Ecto that I want to treat it as a binary_id? Regards, Michael
You need to tell your Ecto schema that you want the id to be a UUID (just putting it in the migration is not enough as you are seeing).
To do so you need to set the @primary_key module attribute (docs)
@primary_key - configures the schema primary key. It expects a tuple {field_name, type, options} with the primary key field name, type (typically :id or :binary_id, but can be any type) and options. It also accepts false to disable the generation of a primary key field. Defaults to {:id, :id, autogenerate: true}.
For you it will look like:
@primary_key {:id, :binary_id}
schema "channels" do
belongs_to :owner, User
field :name, :string
field :description, :string
# rest of schema
end
end
Note: you may also want to set autogenerate: true and if your other schemas are also using UUIDs as primary keys then you will probably want @foreign_key_type :binary_id.
You may also want to define a common schema file that will set those for each of your schema (there’s an example of this in the docs).
To complete the answer once you’ve fixed your existing modules with the previous advice, mix help phx.gen.schema will also help out getting the settings right. In particular:
binary_id
Generated migration can use binary_id for schema’s primary key and its
references with option --binary-id.
Default options
This generator uses default options provided in the :generators configuration
of your application. These are the defaults:
You can override those options per invocation by providing corresponding
switches, e.g. --no-binary-id to use normal ids despite the default
configuration or --migration to force generation of the migration.
So you can change your generators setting in config.exs to binary_id: true and it will ensure all your generated schemas and migrations will work with UUIDs properly from then on.
So I’m migrating my User schema to binary_id and I’m hitting a similar issue when I’m attempting to confirm a registered user with the UserToken schema:
** (Ecto.Query.CastError) lib/faithful_word/accounts.ex:421: value `"a172f965-454b-47be-b246-35864825c646"` in `where` cannot be cast to type :id in query:
from u0 in FaithfulWord.Schema.UserToken,
where: u0.user_id == ^"a172f965-454b-47be-b246-35864825c646",
where: u0.org_id == ^1
here is the code where it’s failing:
def build_user_confirmation_token(%User{} = user, %Org{} = org) do
if org.id in user.orgs_confirmed do
{:error, :already_confirmed}
else
# remove previous attempts to register
Repo.delete_all(from(ut in UserToken, where: ut.user_id == ^user.id, where: ut.org_id == ^org.id)) # user.id mis-cast
{encoded_token, user_token} = UserToken.build_email_token(user, "confirm", org.id)
Repo.insert!(user_token)
{:ok, encoded_token, user_token}
end
end
Ecto seems to think the User :binary_id is just :id? Here is my User and UserToken:
I’m pretty sure it’s something I’m missing in user.ex but I’m not sure what …
You have to replicate the same process on your user_token schema and "users_tokens" table as you did for your users.
It looks like you haven’t let it know that it is expecting a foreign key with a binary id?
Here’s what mine looks like for reference, schema:
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "people_tokens" do
...
end
...
Edit: I think you just need to let your schema on your user_token know that it is expecting the :user_id to be a :binary_id by the @foreign_key_type :binary_id.