Why does Ecto's `cast` not convert an integer

2019-07-06 00:54发布

I have an Ecto schema that includes field :owned_by_id, :string. I declared the field a string because I need to support values like "abc123" as well as values like "123".

The docs for cast/3 say:

The second argument is a map of params that are cast according to the type information from data.

In my module, I define changeset like:

def changeset(struct, params \\ %{}) do
  cast(struct, params, [:owned_by_id])
end

When I do this:

MyModule.changeset(%MyModule{}, %{owned_by_id: 1})

... I would expect cast to turn that owned_by_id integer param into a string, based on the field declaration.

However, what I get instead is a changeset that includes

errors: [owned_by_id: {"is invalid", [type: :string]}]

I could call Integer.to_string(1) myself, but shouldn't cast handle that? Is there a way to have it handle this automatically?

标签: elixir ecto
2条回答
劳资没心,怎么记你
2楼-- · 2019-07-06 01:33

If you want a plug and play solution, you can use this hex package that I have created. https://github.com/luizParreira/ecto_cast_to_string

查看更多
看我几分像从前
3楼-- · 2019-07-06 01:47

While the docs do say that the params are "cast according to the type information", Ecto does not implement casting for Integer -> String. My guess would be that's because this is rarely needed while the String -> Integer conversion is useful for when the input is sent via a web form where all the fields arrive as strings.


You can create a custom type if you want this kind of conversion. The documentation has an example of a custom type that implements something similar: https://github.com/elixir-ecto/ecto/blob/d40008db48ec26967b847c3661cbc0dbaf847454/lib/ecto/type.ex#L29-L40

Your type would look something like:

def type, do: :string

def cast(integer) when is_integer(integer) do
  {:ok, Integer.to_string(integer)}
end
def cast(string) when is_binary(string), do: {:ok, string}
def cast(_), do: :error

...

Note: I wouldn't recommend doing this. In my opinion, an explicit conversion would be simpler unless you're implementing something complex like the documentation example I've linked to above.

查看更多
登录 后发表回答