Skip to content

Commit c4bb74a

Browse files
authored
Improve warning/error message for writable violations (#4738)
1 parent 2e59540 commit c4bb74a

2 files changed

Lines changed: 50 additions & 10 deletions

File tree

lib/ecto/repo/schema.ex

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,15 @@ defmodule Ecto.Repo.Schema do
665665
defp handle_writable_violation(field, schema, action) do
666666
on_writable_violation = schema.__schema__(:on_writable_violation, field)
667667

668-
message = "attempted to write to non-writable field #{inspect(field)} during #{action}"
668+
message = """
669+
you are attempting to write to the field #{inspect(field)} of #{inspect(schema)} but
670+
the `:writable` option of this field indicates the field should not be written to during an #{action}.
671+
672+
If you want to write to this field, please set the appropriate `:writable` option when defining the field.
673+
674+
If you want to customize the behavior of writing to a non-writable field,
675+
please set the appropriate `:on_writable_violation` option when defining the field.
676+
"""
669677

670678
case on_writable_violation do
671679
:raise ->

test/ecto/repo_test.exs

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2458,18 +2458,35 @@ defmodule Ecto.RepoTest do
24582458
assert_received {:update, %{changes: [always: 10]}}
24592459
end)
24602460

2461-
assert log =~ "attempted to write to non-writable field :insert during update"
2462-
assert log =~ "attempted to write to non-writable field :never during update"
2461+
assert log =~ ~r"""
2462+
you are attempting to write to the field :insert of #{inspect(__MODULE__.MySchemaWritableWarn)} but
2463+
the `:writable` option of this field indicates the field should not be written to during an update.
2464+
"""
2465+
2466+
assert log =~ ~r"""
2467+
you are attempting to write to the field :never of #{inspect(__MODULE__.MySchemaWritableWarn)} but
2468+
the `:writable` option of this field indicates the field should not be written to during an update.
2469+
"""
24632470
end
24642471

24652472
test "update with on_writable_violation: :raise saves changes for writable: :always and raises for changes for writable: :insert/:never" do
2466-
assert_raise ArgumentError, "attempted to write to non-writable field :never during update", fn ->
2473+
never_message = ~r"""
2474+
you are attempting to write to the field :never of #{inspect(__MODULE__.MySchemaWritableRaise)} but
2475+
the `:writable` option of this field indicates the field should not be written to during an update.
2476+
"""
2477+
2478+
assert_raise ArgumentError, never_message, fn ->
24672479
%MySchemaWritableRaise{id: 1}
24682480
|> Ecto.Changeset.change(%{never: 10})
24692481
|> TestRepo.update!()
24702482
end
24712483

2472-
assert_raise ArgumentError, "attempted to write to non-writable field :insert during update", fn ->
2484+
insert_message = ~r"""
2485+
you are attempting to write to the field :insert of #{inspect(__MODULE__.MySchemaWritableRaise)} but
2486+
the `:writable` option of this field indicates the field should not be written to during an update.
2487+
"""
2488+
2489+
assert_raise ArgumentError, insert_message, fn ->
24732490
%MySchemaWritableRaise{id: 2}
24742491
|> Ecto.Changeset.change(%{insert: 11})
24752492
|> TestRepo.update!()
@@ -2552,7 +2569,10 @@ defmodule Ecto.RepoTest do
25522569
assert Enum.sort(inserted_fields) == [always: 10, id: 1, insert: 12]
25532570
end)
25542571

2555-
assert log =~ "attempted to write to non-writable field :never during insert"
2572+
assert log =~ ~r"""
2573+
you are attempting to write to the field :never of #{inspect(__MODULE__.MySchemaWritableWarn)} but
2574+
the `:writable` option of this field indicates the field should not be written to during an insert.
2575+
"""
25562576
end
25572577

25582578
test "insert with on_writable_violation: :warn saves changes for writable: :always/:insert, ignores changes for writable: :never, and logs a warning" do
@@ -2566,17 +2586,24 @@ defmodule Ecto.RepoTest do
25662586
assert Enum.sort(inserted_fields) == [always: 10, id: 1, insert: 12]
25672587
end)
25682588

2569-
assert log =~ "attempted to write to non-writable field :never during insert"
2589+
assert log =~ ~r"""
2590+
you are attempting to write to the field :never of #{inspect(__MODULE__.MySchemaWritableWarn)} but
2591+
the `:writable` option of this field indicates the field should not be written to during an insert.
2592+
"""
25702593
end
25712594

25722595
test "insert with surfaced changes and on_writable_violation: :raise saves changes for writable: :always/:insert and raises for changes for writable: :never" do
2573-
assert_raise ArgumentError, "attempted to write to non-writable field :never during insert", fn ->
2596+
message = ~r"""
2597+
you are attempting to write to the field :never of #{inspect(__MODULE__.MySchemaWritableRaise)} but
2598+
the `:writable` option of this field indicates the field should not be written to during an insert.
2599+
"""
2600+
2601+
assert_raise ArgumentError, message, fn ->
25742602
%MySchemaWritableRaise{id: 1, never: 10}
25752603
|> Ecto.Changeset.change(%{})
25762604
|> TestRepo.insert!()
25772605
end
25782606

2579-
25802607
%MySchemaWritableRaise{id: 2, insert: 11, always: 12}
25812608
|> Ecto.Changeset.change(%{})
25822609
|> TestRepo.insert!()
@@ -2586,7 +2613,12 @@ defmodule Ecto.RepoTest do
25862613
end
25872614

25882615
test "insert with on_writable_violation: :raise saves changes for writable: :always/:insert and raises for changes for writable: :never" do
2589-
assert_raise ArgumentError, "attempted to write to non-writable field :never during insert", fn ->
2616+
message = ~r"""
2617+
you are attempting to write to the field :never of #{inspect(__MODULE__.MySchemaWritableRaise)} but
2618+
the `:writable` option of this field indicates the field should not be written to during an insert.
2619+
"""
2620+
2621+
assert_raise ArgumentError, message, fn ->
25902622
%MySchemaWritableRaise{id: 1}
25912623
|> Ecto.Changeset.change(%{never: 10})
25922624
|> TestRepo.insert!()

0 commit comments

Comments
 (0)