Sparse field param for function based attribute breaks
I have a serializer defined like this:
attributes([
:name,
:custom_property
])
Where :name exists in the original struct, but :custom_property is calculated in same named function.
If I try to use sparse fields that include the custom property via e.g. fields[record]=custom-property, it breaks when trying to convert from dashed to underscored key value while building the attributes (error details below).
A fix for this is to just apply formatting while doing the conversion. E.g. in JaSerializer.Builder.Utils.safe_atom_list/1:
def safe_atom_list(field_str) do
field_str
|> String.split(",")
|> Enum.map(&JaSerializer.ParamParser.Utils.format_key/1) # <---- this is the fix
|> Enum.map(&String.to_existing_atom/1)
end
After that, it all seems to be working fine. I can turn this into a PR, but I am not sure if this is the right place to fix the issue.
And, here is the stack trace:
* (exit) an exception was raised:
** (ArgumentError) argument error
:erlang.binary_to_existing_atom("custom-property", :utf8)
(elixir 1.10.3) lib/string.ex:2303: String.to_existing_atom/1
(elixir 1.10.3) lib/enum.ex:1396: Enum."-map/2-lists^map/1-0-"/2
(elixir 1.10.3) lib/enum.ex:1396: Enum."-map/2-lists^map/1-0-"/2
(ja_serializer 0.16.0) lib/ja_serializer/builder/attribute.ex:37: JaSerializer.Builder.Attribute.do_filter/2
(ja_serializer 0.16.0) lib/ja_serializer/builder/attribute.ex:11: JaSerializer.Builder.Attribute.build/1
(ja_serializer 0.16.0) lib/ja_serializer/builder/resource_object.ex:23: JaSerializer.Builder.ResourceObject.build/1
(elixir 1.10.3) lib/enum.ex:1396: Enum."-map/2-lists^map/1-0-"/2
(ja_serializer 0.16.0) lib/ja_serializer/builder/top_level.ex:34: JaSerializer.Builder.TopLevel.build/1
(ja_serializer 0.16.0) lib/ja_serializer.ex:62: JaSerializer.format/4
(phoenix 1.4.17) lib/phoenix/view.ex:410: Phoenix.View.render_to_iodata/3
P.S. If it helps, I also have a workaround. In controller, I apply this transformation to the sparse fields params:
defp underscore(nil), do: nil
defp underscore(string) when is_binary(string), do: String.replace(string, "-", "_")
defp underscore(%{} = map) do
map
|> Enum.map(fn {key, value} ->
{key, underscore(value)}
end)
|> Enum.into(%{})
end
Used like this:
render(conn, "index.json",
data: some_data,
opts: [
fields: underscore(params["fields"])
]
)
@elvanja sorry I haven't had a chance to look at this yet. It seems like this should affect any sparse field name that needs to get converted from dashes to underscore. If the regular (non-custom) property name has an underscore, does that break too?
Hi! Sure, no problemo, it is not an emergency 😄 And yes, the non-custom properties also break, on main record or on relations.