mirror of
https://github.com/ash-project/ash.git
synced 2024-09-19 21:13:10 +12:00
fix: we cannot assume that after_action/1
can be done atomically
The reason for this is that a given change may access `changeset.data` which will not be available. This may introduce compile errors for some users unfortunately, there is nothing we can do about this. They will need to change to writing custom changes w/ the `atomic/3` callback that adds an after action hook improvement: honor a `_union_type` type param when casting unions
This commit is contained in:
parent
5b89286854
commit
cb3facb519
5 changed files with 59 additions and 6 deletions
|
@ -1739,7 +1739,7 @@ Declares a `destroy` action. For calling this action, see the `Ash.Domain` docum
|
|||
|
||||
### Examples
|
||||
```
|
||||
destroy :soft_delete do
|
||||
destroy :destroy do
|
||||
primary? true
|
||||
end
|
||||
|
||||
|
|
|
@ -14,8 +14,10 @@ defmodule Ash.Resource.Change.AfterAction do
|
|||
)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def atomic(changeset, opts, context) do
|
||||
{:ok, change(changeset, opts, context)}
|
||||
end
|
||||
# we had to remove this. We can't be sure that the change function won't access
|
||||
# `changeset.data`, so cannot do this automatically
|
||||
# @impl true
|
||||
# def atomic(changeset, opts, context) do
|
||||
# {:ok, change(changeset, opts, context)}
|
||||
# end
|
||||
end
|
||||
|
|
|
@ -679,7 +679,7 @@ defmodule Ash.Resource.Dsl do
|
|||
""",
|
||||
examples: [
|
||||
"""
|
||||
destroy :soft_delete do
|
||||
destroy :destroy do
|
||||
primary? true
|
||||
end
|
||||
"""
|
||||
|
|
|
@ -406,6 +406,18 @@ defmodule Ash.Type.Union do
|
|||
end
|
||||
end
|
||||
|
||||
def cast_input(%{"_union_type" => union_type} = value, constraints) do
|
||||
case Enum.find(constraints[:types], fn {key, _} ->
|
||||
to_string(key) == union_type
|
||||
end) do
|
||||
{type, _config} ->
|
||||
cast_input(%Ash.Union{value: Map.delete(value, "_union_type"), type: type}, constraints)
|
||||
|
||||
_ ->
|
||||
cast_input(Map.delete(value, "_union_type"), constraints)
|
||||
end
|
||||
end
|
||||
|
||||
def cast_input(value, constraints) do
|
||||
types = constraints[:types] || []
|
||||
|
||||
|
|
|
@ -60,6 +60,21 @@ defmodule Ash.Test.Actions.BulkCreateTest do
|
|||
end
|
||||
end
|
||||
|
||||
defmodule ChangeTitleBeforeAction do
|
||||
use Ash.Resource.Change
|
||||
|
||||
@impl Ash.Resource.Change
|
||||
def change(changeset, _opts, _context) do
|
||||
Ash.Changeset.before_action(changeset, fn changeset ->
|
||||
Ash.Changeset.force_change_attribute(
|
||||
changeset,
|
||||
:title,
|
||||
"before_" <> Ash.Changeset.get_attribute(changeset, :title)
|
||||
)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
defmodule ChangeMessage do
|
||||
use Ash.Resource.Change
|
||||
|
||||
|
@ -206,6 +221,11 @@ defmodule Ash.Test.Actions.BulkCreateTest do
|
|||
default_accept :*
|
||||
defaults [:read, :destroy, create: :*, update: :*]
|
||||
|
||||
create :create_with_before_action do
|
||||
accept [:title]
|
||||
change ChangeTitleBeforeAction
|
||||
end
|
||||
|
||||
create :create_with_related_posts do
|
||||
argument :related_post_ids, {:array, :uuid} do
|
||||
allow_nil? false
|
||||
|
@ -547,6 +567,25 @@ defmodule Ash.Test.Actions.BulkCreateTest do
|
|||
)
|
||||
end
|
||||
|
||||
test "runs before action hooks" do
|
||||
org =
|
||||
Org
|
||||
|> Ash.Changeset.for_create(:create, %{})
|
||||
|> Ash.create!()
|
||||
|
||||
assert %Ash.BulkResult{records: [%{title: "before_title1"}, %{title: "before_title2"}]} =
|
||||
Ash.bulk_create!(
|
||||
[%{title: "title1"}, %{title: "title2"}],
|
||||
Post,
|
||||
:create_with_before_action,
|
||||
return_records?: true,
|
||||
return_errors?: true,
|
||||
authorize?: false,
|
||||
sorted?: true,
|
||||
tenant: org.id
|
||||
)
|
||||
end
|
||||
|
||||
test "runs changes" do
|
||||
org =
|
||||
Org
|
||||
|
|
Loading…
Reference in a new issue