Post param parsed as integer

So I have my form with those fields POSTed:

utf8: ✓
_csrf_token: a1ILBA0eGSJSJggHJ25GYj8IIEACShkC8bgoudFN8DcUCC01EIT2Mxjl
_method: put
certification[id]: 10
certification[is_active]: true
certification[rncp_id]: 367
certification[acronym]: Diplôme
certification[level]: 7
commit: Update Certification

But on the server side, once the params are parsed, I get the following map:

%{
  id: 10,
  is_active: true,
  rncp_id: 367,
  acronym: "Diplôme",
  level: "7"
}

:id is an integer so I’m happy it was parsed, but neither :rncp_id nor :level are. Why does :rncp_id gets parsed as integer while :level correctly won’t?

I’m guessing this is because its name finishes with _id, but could this any how make sense here?

This breaks my changeset afterwards, with some: errors: [rncp_id: {"is invalid", [type: :string, validation: :cast]}] error. :frowning_face:

Why is this happening? Why such subjective rule if so? Anyway the fields are casted afterwards so it wouldn’t matter to keep it as a string.

Anyway, I’ll go for a dirty:

    params = case params[:rncp_id] do
      v when is_integer(v) -> Map.put(params, :rncp_id, Integer.to_string(v))
      _ -> params
    end

for now.

Thanks

Where do you assert the parsed params and how do you trigger it (test or browser)? Generally form params are not type converted at all. Casting them with ecto is the only thing doing that.

You likely have something like Ecto.Changeset.cast(..., params["certification"]) in your controller, or in a plug. And it’s likely casted to an Ecto model which has these rules.

I’d look for where this is happening - the shape you showed (atom-keyed map) isn’t the default behavior for Phoenix (string-keyed map). Maybe there’s a plug in the router or the endpoint that’s doing additional parsing?

1 Like