11defmodule CodeCorpsWeb.Plug.DataToAttributes do
22 @moduledoc ~S"""
3- Converts params in the JSON api "data" format into flat params convient for
3+ Converts params in the JSON api format into flat params convient for
44 changeset casting.
55
6- This is done using `JaSerializer.Params.to_attributes/1`
6+ For base parameters, this is done using `JaSerializer.Params.to_attributes/1`
7+
8+ For included records, this is done using custom code.
79 """
810
911 alias Plug.Conn
@@ -12,13 +14,38 @@ defmodule CodeCorpsWeb.Plug.DataToAttributes do
1214 def init(opts), do: opts
1315
1416 @spec call(Conn.t, Keyword.t) :: Plug.Conn.t
15- def call(%Conn{params: %{"data" => data } = params} = conn, _opts ) do
17+ def call(%Conn{params: %{} = params} = conn, opts \\ [] ) do
1618 attributes =
1719 params
1820 |> Map.delete("data")
19- |> Map.merge(data |> JaSerializer.Params.to_attributes)
21+ |> Map.delete("included")
22+ |> Map.merge(params |> parse_data())
23+ |> Map.merge(params |> parse_included(opts))
2024
2125 conn |> Map.put(:params, attributes)
2226 end
23- def call(%Conn{} = conn, _opts), do: conn
27+
28+ @spec parse_data(map) :: map
29+ defp parse_data(%{"data" => data}), do: data |> JaSerializer.Params.to_attributes
30+ defp parse_data(%{}), do: %{}
31+
32+ @spec parse_included(map, Keyword.t) :: map
33+ defp parse_included(%{"included" => included}, opts) do
34+ included |> Enum.reduce(%{}, fn (%{"data" => %{"type" => type}} = params, parsed) ->
35+ attributes = params |> parse_data()
36+
37+ if opts |> Keyword.get(:includes_many, []) |> Enum.member?(type) do
38+ # this is an explicitly specified has_many,
39+ # update existing data by adding new record
40+ pluralized_type = type |> Inflex.pluralize
41+ parsed |> Map.update(pluralized_type, [attributes], fn data ->
42+ data ++ [attributes]
43+ end)
44+ else
45+ # this is a belongs to, put a new submap into payload
46+ parsed |> Map.put(type, attributes)
47+ end
48+ end)
49+ end
50+ defp parse_included(%{}, _opts), do: %{}
2451end
0 commit comments