I finally came up with a solution without the need of two models (for ecto and my app). I have only one model that I implemented like this :
defmodule Dbuniverse.Character do
use Ecto.Schema
import Ecto.Changeset
@required_fields [:name, :description]
@optional_fields [:category, :image_url, :type]
schema "character" do
field :category, :string
field :name, :string
field :image_url, :string
field :description, :string
field :type, :string
timestamps()
end
def create_new_character(character, params \\ %{}) do
character
|> cast(params, @required_fields ++ @optional_fields)
|> validate_required(@required_fields)
end
end
I then created, in both edit and create actions of my controller, a changeset and passed it to my edit page :
def create(conn, _params) do
changeset = Character.create_new_character(%Character{}, %{:name => "", :description => ""})
render conn, "edit.html", [changeset: changeset, options: %{}]
end
def edit(conn, %{"id" => id}) do
character = Dbuniverse.Repo.get_by_id id
changeset = Character.create_new_character(
%Character{},
%{
:name => character["name"],
:description => character["description"],
:category => character["category"],
:image_url => character["image_url"]
}
)
# IO.inspect changeset
render conn, "edit.html", [changeset: changeset, options: %{id: id, rev: character["_rev"]}]
end
For both add and update actions, I get the changeset back from the form and then pass it to my repo methods :
def add(conn, %{"character" => character}) do
character = Map.put(character, :type, "character")
character = Poison.encode! character
json = Dbuniverse.Repo.insert character
redirect conn, to: character_path(conn, :show, json["id"])
end
def update(conn, %{"character" => character, "id" => id, "rev" => rev}) do
IO.inspect character
character = Map.put(character, :_rev, rev)
character = Map.put(character, :type, "character")
IO.inspect character
Dbuniverse.Repo.update(Poison.encode!(character), id)
redirect conn, to: character_path(conn, :show, id)
end
My form finally looks like this :
<h1>Edit character</h1>
<%= form_for @changeset, create_or_update_action(@conn, @options), fn f -> %>
<div class="form-group">
<%= label f, :name, "Nom" %>
<%= text_input f, :name, class: "form-control" %>
</div>
<div class="form-group">
<%= label f, :description, "Description" %>
<%= textarea f, :description, class: "form-control", rows: 5 %>
</div>
<div class="form-group">
<%= label f, :image_url, "Url" %>
<%= text_input f, :image_url, class: "form-control" %>
</div>
<div class="form-group">
<%= label f, :category, "category" %>
<%= text_input f, :category, class: "form-control" %>
</div>
<%= submit "Add", class: "btn btn-primary pull-right" %>
<% end %>
The create_or_update_action comes from my character’s view and determines to which action should the form post the data :
defmodule DbuniverseWeb.CharacterView do
use DbuniverseWeb.Web, :view
def create_or_update_action(conn, %{"id": id, "rev": rev}) do
character_path(conn, :update, id, rev)
end
def create_or_update_action(conn, %{}) do
character_path(conn, :create)
end
end