From f4bf715b74359dd2b93b3e553d61f92cb0f5f0f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aziz=20K=C3=B6ksal?= Date: Tue, 1 Oct 2024 15:29:47 +0200 Subject: [PATCH 1/2] `apply_changes/1`: convert nested schemaless validations --- lib/ecto/changeset.ex | 3 +++ test/ecto/changeset_test.exs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/ecto/changeset.ex b/lib/ecto/changeset.ex index cd0daeffe9..8dd37b1a5f 100644 --- a/lib/ecto/changeset.ex +++ b/lib/ecto/changeset.ex @@ -2208,6 +2208,9 @@ defmodule Ecto.Changeset do {:ok, {tag, relation}} when tag in @relations -> apply_relation_changes(acc, key, relation, value) + {:ok, :map} when is_struct(value, Changeset) -> + Map.put(acc, key, apply_changes(value)) + {:ok, _} -> Map.put(acc, key, value) diff --git a/test/ecto/changeset_test.exs b/test/ecto/changeset_test.exs index 69e4400ee7..41e50c2d86 100644 --- a/test/ecto/changeset_test.exs +++ b/test/ecto/changeset_test.exs @@ -1073,6 +1073,23 @@ defmodule Ecto.ChangesetTest do assert changed_post.category == nil end + test "apply_changes/1 with nested schemaless validation" do + params = %{"seo_metadata" => %{"keywords" => ["foo", "bar"], "slug" => "my-post-1"}} + + changeset = + %Post{} + |> changeset(params) + |> update_change(:seo_metadata, fn seo_metadata -> + {%{}, %{keywords: {:array, :string}, slug: :string}} + |> cast(seo_metadata || %{}, [:keywords, :slug]) + |> validate_required([:keywords, :slug]) + end) + + changed_post = apply_changes(changeset) + + assert changed_post.seo_metadata == %{keywords: ["foo", "bar"], slug: "my-post-1"} + end + describe "apply_action/2" do test "valid changeset" do post = %Post{} From 1ea1005d4d42ea673615af790dbfd85983dd968c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aziz=20K=C3=B6ksal?= Date: Wed, 2 Oct 2024 21:11:05 +0200 Subject: [PATCH 2/2] Added comment to `apply_changes/1` doc --- lib/ecto/changeset.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/ecto/changeset.ex b/lib/ecto/changeset.ex index 8dd37b1a5f..a5051b0838 100644 --- a/lib/ecto/changeset.ex +++ b/lib/ecto/changeset.ex @@ -2190,6 +2190,9 @@ defmodule Ecto.Changeset do regardless if the changeset is valid or not. See `apply_action/2` for a similar function that ensures the changeset is valid. + If a field of type `:map` contains a schemaless changeset, + its changes too will be applied and returned as a map with atom keys. + ## Examples iex> changeset = change(%Post{author: "bar"}, %{title: "foo"})