Skip to content

Commit

Permalink
Support arity 3 cast functions (#166)
Browse files Browse the repository at this point in the history
elixir-ecto/ecto#4178 added support for using
an arity three cast function. This commit adds support to phoenix_ecto
as well.
  • Loading branch information
SteffenDE committed Jun 3, 2023
1 parent ea64955 commit ec62653
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 6 deletions.
26 changes: 20 additions & 6 deletions lib/phoenix_ecto/html.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ if Code.ensure_loaded?(Phoenix.HTML) do

for changeset <- skip_replaced(changesets) do
%{data: data, params: params} =
changeset = to_changeset(changeset, parent_action, module, cast)
changeset = to_changeset(changeset, parent_action, module, cast, nil)

%Phoenix.HTML.Form{
source: changeset,
Expand Down Expand Up @@ -82,7 +82,7 @@ if Code.ensure_loaded?(Phoenix.HTML) do

for {changeset, index} <- Enum.with_index(changesets) do
%{data: data, params: params} =
changeset = to_changeset(changeset, parent_action, module, cast)
changeset = to_changeset(changeset, parent_action, module, cast, index)

index_string = Integer.to_string(index)

Expand Down Expand Up @@ -233,17 +233,20 @@ if Code.ensure_loaded?(Phoenix.HTML) do
end
end

defp to_changeset(%Ecto.Changeset{} = changeset, parent_action, _module, _cast),
defp to_changeset(%Ecto.Changeset{} = changeset, parent_action, _module, _cast, _index),
do: apply_action(changeset, parent_action)

defp to_changeset(%{} = data, parent_action, _module, cast) when is_function(cast, 2),
defp to_changeset(%{} = data, parent_action, _module, cast, _index) when is_function(cast, 2),
do: apply_action(cast!(cast, data), parent_action)

defp to_changeset(%{} = data, parent_action, _module, {module, func, arguments} = mfa)
defp to_changeset(%{} = data, parent_action, _module, cast, index) when is_function(cast, 3),
do: apply_action(cast!(cast, data, index), parent_action)

defp to_changeset(%{} = data, parent_action, _module, {module, func, arguments} = mfa, _imdex)
when is_atom(module) and is_atom(func) and is_list(arguments),
do: apply_action(apply!(mfa, data), parent_action)

defp to_changeset(%{} = data, parent_action, _module, nil),
defp to_changeset(%{} = data, parent_action, _module, nil, _index),
do: apply_action(Ecto.Changeset.change(data), parent_action)

defp cast!(cast, data) do
Expand All @@ -257,6 +260,17 @@ if Code.ensure_loaded?(Phoenix.HTML) do
end
end

defp cast!(cast, data, index) do
case cast.(data, %{}, index) do
%Ecto.Changeset{} = changeset ->
changeset

other ->
raise "expected on_cast/3 callback #{inspect(cast)} to return an Ecto.Changeset, " <>
"got: #{inspect(other)}"
end
end

defp apply!({module, func, arguments}, data) do
case apply(module, func, [data, %{} | arguments]) do
%Ecto.Changeset{} = changeset ->
Expand Down
20 changes: 20 additions & 0 deletions test/phoenix_ecto/inputs_for_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,26 @@ defmodule PhoenixEcto.InputsForTest do
~s(<input id="user_comments_1_body" name="user[comments][1][body]" type="text" value="data2">)
end

test "has many: inputs/for/4 with custom changeset with arity 3" do
changeset =
%User{comments: [%Comment{body: "data1"}, %Comment{body: "data2"}]}
|> cast(%{}, ~w()a)
|> cast_assoc(:comments, with: &Comment.changeset_with_position/3)

contents =
safe_inputs_for(
changeset,
:comments,
fn f ->
number_input(f, :position)
end
)

assert contents ==
~s(<input id="user_comments_0_position" name="user[comments][0][position]" type="number" value="0">) <>
~s(<input id="user_comments_1_position" name="user[comments][1][position]" type="number" value="1">)
end

## inputs_for embeds one

test "embeds one: inputs_for/4" do
Expand Down
6 changes: 6 additions & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ defmodule Comment do

schema "comments" do
field :body
field :position, :integer
end

def changeset(comment, params) do
Expand All @@ -38,6 +39,11 @@ defmodule Comment do
|> cast(params, ~w(body)a)
|> validate_length(:body, min: required_length)
end

def changeset_with_position(comment, params, index) do
changeset(comment, params)
|> Ecto.Changeset.put_change(:position, index)
end
end

defmodule User do
Expand Down

0 comments on commit ec62653

Please sign in to comment.