Skip to content

Instantly share code, notes, and snippets.

@stevedomin
Created October 4, 2014 17:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stevedomin/1444240501ee4ca30b30 to your computer and use it in GitHub Desktop.
Save stevedomin/1444240501ee4ca30b30 to your computer and use it in GitHub Desktop.
Avoid encoding/decoding in controller create
def create(conn, %{"user" => u}) do
user = struct(User, u)
IO.inspect user
# %App.User{created_at: nil, email: nil}
end
def create(conn, %{"user" => user}) do
user = struct(User, JSON.encode!(u) |> JSON.decode!(keys: :atoms!))
IO.inspect user
# %App.User{created_at: nil, email: "test@email.com"}
end
@chrismccord
Copy link

def create(conn, %{"user" => u}) do
  user = User.from_map(u)
end

defmodule User do
  defstruct name: nil, age: 123

  @safed_keys Map.from_struct(%__MODULE__{}) |> Map.keys |> Enum.map(&to_string/1)

  def from_map(map) do
    struct(User, for {key, val} <- map, to_string(key) in @safed_keys do
      case key do
        k when is_binary(k) -> {String.to_atom(k), val}
        k when is_atom(k)   -> {k, val}
      end
    end)
  end
end

iex(24)> User.from_map(%{"name" => "chris"})
%User{age: 123, name: "chris"}
iex(25)> User.from_map(%{"name" => "chris", "email" => "sklflsfj"})
%User{age: 123, name: "chris"}
iex(26)> User.from_map(%{name: "chris", email: "sklflsfj"})
%User{age: 123, name: "chris"}

@chrismccord
Copy link

defmodule SafeMapToStruct do
  defmacro __using__(_opts) do
    quote do
      @before_compile unquote(__MODULE__)
    end
  end

  defmacro __before_compile__(_env) do
    quote do
      @safed_keys Map.from_struct(%__MODULE__{}) |> Map.keys |> Enum.map(&to_string/1)
      def from_map(map) do
        SafeMapToStruct.from_map(map, __MODULE__, @safed_keys)
      end
    end
  end

  def from_map(map, module, safed_keys) do
    struct(module, for {key, val} <- map, to_string(key) in safed_keys do
      case key do
        k when is_binary(k) -> {String.to_atom(k), val}
        k when is_atom(k)   -> {k, val}
      end
    end)
  end
end

defmodule User do
  use SafeMapToStruct
  defstruct name: nil, age: 123

end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment