Current section

Files

Jump to
formex lib builder.ex
Raw

lib/builder.ex

defmodule Formex.Builder do
import Ecto.Changeset
alias Formex.Form
@repo Application.get_env(:formex, :repo)
@moduledoc """
The form builder.
Example:
```
form = create_form(App.ArticleType, %Article{})
render(conn, "new.html", form: form)
```
```
App.ArticleType
|> create_form(%Article{}, article_params)
|> insert_form_data
|> case do
{:ok, _article} ->
# ...
{:error, form} ->
# ...
end
```
"""
@doc """
Creates a form struct.
## Arguments
* `type` - the module that implements `Formex.Type`, for example: `App.ArticleType`
* `struct` - the struct that will be used in `Ecto.Changeset.cast`, for example: `%App.Article{}`
* `params` - params that will be used in `Ecto.Changeset.cast`
"""
@spec create_form(module, Ecto.Schema.t, Map.t) :: Form.t
def create_form(type, struct, params \\ %{}) do
%Form{
type: type,
struct: struct,
model: struct.__struct__,
params: params
}
|> type.build_form()
|> create_changeset(type)
# |> IO.inspect
end
@doc """
Invokes `Repo.insert`. In case of `:error` returns `{:error, form}` (with new `form.changeset`
value) instead of `{:error, changeset}` (as Ecto does)
"""
@spec insert_form_data(Form.t) :: {:ok, Ecto.Schema.t} | {:error, Form.t}
def insert_form_data(form) do
case @repo.insert(form.changeset) do
{:ok, schema} -> {:ok, schema}
{:error, changeset} -> {:error, Map.put(form, :changeset, changeset)}
end
end
@doc """
Invokes `Repo.update`. In case of `:error` returns `{:error, form}` (with new `form.changeset`
value) instead of `{:error, changeset}` (as Ecto does)
"""
@spec update_form_data(Form.t) :: {:ok, Ecto.Schema.t} | {:error, Form.t}
def update_form_data(form) do
case @repo.update(form.changeset) do
{:ok, schema} -> {:ok, schema}
{:error, changeset} -> {:error, Map.put(form, :changeset, changeset)}
end
end
#
defp create_changeset(form, type) do
changeset = form.struct
|> cast(form.params, get_normal_fields_names(form))
|> validate_required(get_required_fields_names(form))
|> type.changeset_after_create_callback
form
|> Map.put(:changeset, changeset)
end
defp get_normal_fields_names(form) do
form.fields
# |> Enum.filter(&(!&1.assoc))
|> Enum.map(&(&1.name))
end
# defp get_assoc_fields_names(form) do
# form.fields
# |> Enum.filter(&(&1.assoc))
# |> Enum.map(&(&1.name))
# end
defp get_required_fields_names(form) do
form.fields
|> Enum.filter(&(&1.required))
|> Enum.map(&(&1.name))
end
end