Repository: elixir-ecto/ecto
Pull request #2360 (2017-12-25 14:51:01)

correctly log validate_confirmation in Changeset
All other validations record `{field, {:validation_type, opts}}` in the Changeset's `validations` field, but `validate_confirmation` logs `{:validation, opts}` instead. I believe this is a regression introduced in #1739.

ebert[bot]: Hello, @voltone! This is your first Pull Request that will be reviewed by [Ebert](https://ebertapp.io/), an automatic Code Review service. It will leave comments on this diff with potential issues and style violations found in the code as you push new commits. You can also see all the issues found on this Pull Request on its [review page](https://ebertapp.io/github/elixir-ecto/ecto/pulls/2360). Please check our [documentation](https://docs.ebertapp.io) for more information. 

Patch:
diff --git a/lib/ecto/changeset.ex b/lib/ecto/changeset.ex
index cc74f4d9..ac5b9da3 100644
--- a/lib/ecto/changeset.ex
+++ b/lib/ecto/changeset.ex
@@ -1792,7 +1792,7 @@ defmodule Ecto.Changeset do
           confirmation_missing(opts, error_field)
       end
 
-    %{changeset | validations: [{:confirmation, opts} | changeset.validations],
+    %{changeset | validations: [{field, {:confirmation, opts}} | changeset.validations],
                   errors: errors ++ changeset.errors,
                   valid?: changeset.valid? and errors == []}
   end


Test patch:
diff --git a/test/ecto/changeset_test.exs b/test/ecto/changeset_test.exs
index a340663f..a51c5fd9 100644
--- a/test/ecto/changeset_test.exs
+++ b/test/ecto/changeset_test.exs
@@ -971,48 +971,57 @@ defmodule Ecto.ChangesetTest do
                 |> validate_confirmation(:title)
     assert changeset.valid?
     assert changeset.errors == []
+    assert changeset.validations == [{:title, {:confirmation, []}}]
 
     changeset = changeset(%{"title" => "title"})
                 |> validate_confirmation(:title)
     assert changeset.valid?
     assert changeset.errors == []
+    assert changeset.validations == [{:title, {:confirmation, []}}]
 
     changeset = changeset(%{"title" => "title"})
                 |> validate_confirmation(:title, required: false)
     assert changeset.valid?
     assert changeset.errors == []
+    assert changeset.validations == [{:title, {:confirmation, [required: false]}}]
 
     changeset = changeset(%{"title" => "title"})
                 |> validate_confirmation(:title, required: true)
     refute changeset.valid?
     assert changeset.errors == [title_confirmation: {"can't be blank", [validation: :required]}]
+    assert changeset.validations == [{:title, {:confirmation, [required: true]}}]
 
     changeset = changeset(%{"title" => "title", "title_confirmation" => nil})
                 |> validate_confirmation(:title)
     refute changeset.valid?
     assert changeset.errors == [title_confirmation: {"does not match confirmation", [validation: :confirmation]}]
+    assert changeset.validations == [{:title, {:confirmation, []}}]
 
     changeset = changeset(%{"title" => "title", "title_confirmation" => "not title"})
                 |> validate_confirmation(:title)
     refute changeset.valid?
     assert changeset.errors == [title_confirmation: {"does not match confirmation", [validation: :confirmation]}]
+    assert changeset.validations == [{:title, {:confirmation, []}}]
 
     changeset = changeset(%{"title" => "title", "title_confirmation" => "not title"})
                 |> validate_confirmation(:title, message: "doesn't match field below")
     refute changeset.valid?
     assert changeset.errors == [title_confirmation: {"doesn't match field below", [validation: :confirmation]}]
+    assert changeset.validations == [{:title, {:confirmation, [message: "doesn't match field below"]}}]
 
     # Skip when no parameter
     changeset = changeset(%{"title" => "title"})
                 |> validate_confirmation(:title, message: "password doesn't match")
     assert changeset.valid?
     assert changeset.errors == []
+    assert changeset.validations == [{:title, {:confirmation, [message: "password doesn't match"]}}]
 
     # With casting
     changeset = changeset(%{"upvotes" => "1", "upvotes_confirmation" => "1"})
                 |> validate_confirmation(:upvotes)
     assert changeset.valid?
     assert changeset.errors == []
+    assert changeset.validations == [{:upvotes, {:confirmation, []}}]
 
     # With blank change
     changeset = changeset(%{"password" => "", "password_confirmation" => "password"})
@@ -1031,6 +1040,7 @@ defmodule Ecto.ChangesetTest do
                 |> validate_confirmation(:password)
     refute changeset.valid?
     assert changeset.errors == []
+    assert changeset.validations == []
   end
 
   test "validate_acceptance/3" do