How to create and update an Ecto field with type "map"?

A table has a field in it which structure can vary from record to record, that’s why I’ve made it a JSON type. Think of “payment_methods” table where “payment_details” is such a json field: for some payment method it’s enough to provide some wallet_id, for others, such as banks, more details are needed. But there’s no common structure. Hence, json.


Now I want to be able to work with said json field on an html page - create a record with it and edit it too.

A part of a migration:

  add(:my_field, :map)

A part of an Elixir model:

field(:my_field, :map)

On an html page I have textarea in which I’ll enter a string such as:

{a: 11, b: 22, c: “afdsafds”}

and then on a server I’ll do:

MyModel.changeset(%MyModel{my_field: params["my_map_data"]})

and it’ll throw an exception:

  errors: [my_field: {"is invalid", [type: :map, validation: :cast]}],

Why? And how to fix it?

Just a guess, but do you make sure to parse the {a: 11, b: 22, c: “afdsafds”} into a map using Jason.decode!/2?

Edit: btw: the keys a, b and c need to be wrapped in double quotes to be valid JSON object keys.

I’ve done both - with Jason.encode!/1, and without it as shown

Why do you say Jason.decode! and not Jason.encode!?
Why Jason.decode!/2 and not Jason.decode!/1? How would I use Jason.decode!/2 ?

Doesn’t the data from the form come as a string? I don’t think Phoenix automagically parses it into an Elixir map. So params["my_map_data"] must contain a string and that’s why the changeset error mentions that the type is invalid.

As a string. That’s why I’ve asked " Why do you say Jason.decode! and not Jason.encode! ?

And yes, simply params["my_map_data"] is wrong

Might not be the root cause, but this is also not valid json. You need quotes around the keys.

That’s what Jason.decode! is used for, to decode a JSON text into an Elixir value. :+1:
You should probably use the Jason.decode function without the ! and check whether you get any errors.