From b92b04c77fa5bfe3d26734d4ee7a19e3b98d99b9 Mon Sep 17 00:00:00 2001 From: Pierre Le Gall Date: Wed, 21 Feb 2024 16:07:17 +0100 Subject: [PATCH] improvement: #133 use resource defined Api (#134) --- lib/ash_phoenix/form/form.ex | 35 +++++++++++++++++++------------- mix.exs | 2 +- mix.lock | 12 +++++------ test/form_test.exs | 33 +++++++++++++++++++++++++++++- test/support/registry.ex | 1 + test/support/resources/artist.ex | 20 ++++++++++++++++++ 6 files changed, 81 insertions(+), 22 deletions(-) create mode 100644 test/support/resources/artist.ex diff --git a/lib/ash_phoenix/form/form.ex b/lib/ash_phoenix/form/form.ex index 32a0864..8cce506 100644 --- a/lib/ash_phoenix/form/form.ex +++ b/lib/ash_phoenix/form/form.ex @@ -460,6 +460,7 @@ defmodule AshPhoenix.Form do name = opts[:as] || "form" id = opts[:id] || opts[:as] || "form" + api = opts[:api] || Ash.Resource.Info.api(resource) {forms, params} = handle_forms( @@ -484,8 +485,8 @@ defmodule AshPhoenix.Form do |> set_accessing_from(opts) {source, opts} = - if opts[:api] || source.api do - Ash.Actions.Helpers.add_process_context(opts[:api] || source.api, source, opts) + if api || source.api do + Ash.Actions.Helpers.add_process_context(api || source.api, source, opts) else {source, opts} end @@ -502,7 +503,7 @@ defmodule AshPhoenix.Form do resource: resource, action: action, type: :create, - api: opts[:api], + api: api, params: params, errors: opts[:errors], transform_errors: opts[:transform_errors], @@ -560,6 +561,7 @@ defmodule AshPhoenix.Form do name = opts[:as] || "form" id = opts[:id] || opts[:as] || "form" + api = opts[:api] || Ash.Resource.Info.api(resource) prepare_source = opts[:prepare_source] || (& &1) @@ -587,8 +589,8 @@ defmodule AshPhoenix.Form do |> set_accessing_from(opts) {source, opts} = - if opts[:api] || source.api do - Ash.Actions.Helpers.add_process_context(opts[:api] || source.api, source, opts) + if api || source.api do + Ash.Actions.Helpers.add_process_context(api || source.api, source, opts) else {source, opts} end @@ -606,7 +608,7 @@ defmodule AshPhoenix.Form do data: data, action: action, type: :update, - api: opts[:api], + api: api, params: params, errors: opts[:errors], transform_errors: opts[:transform_errors], @@ -723,6 +725,7 @@ defmodule AshPhoenix.Form do name = opts[:as] || "form" id = opts[:id] || opts[:as] || "form" + api = opts[:api] || Ash.Resource.Info.api(resource) prepare_source = opts[:prepare_source] || (& &1) {forms, params} = @@ -749,8 +752,8 @@ defmodule AshPhoenix.Form do |> set_accessing_from(opts) {source, opts} = - if opts[:api] || source.api do - Ash.Actions.Helpers.add_process_context(opts[:api] || source.api, source, opts) + if api || source.api do + Ash.Actions.Helpers.add_process_context(api || source.api, source, opts) else {source, opts} end @@ -779,7 +782,7 @@ defmodule AshPhoenix.Form do transform_params: opts[:transform_params], prepare_params: opts[:prepare_params], prepare_source: opts[:prepare_source], - api: opts[:api], + api: api, method: opts[:method] || form_for_method(:destroy), touched_forms: touched_forms(forms, params, opts), form_keys: Keyword.new(List.wrap(opts[:forms])), @@ -821,6 +824,7 @@ defmodule AshPhoenix.Form do name = opts[:as] || "form" id = opts[:id] || opts[:as] || "form" + api = opts[:api] || Ash.Resource.Info.api(resource) {forms, params} = handle_forms( @@ -859,8 +863,8 @@ defmodule AshPhoenix.Form do |> set_accessing_from(opts) {source, opts} = - if opts[:api] || source.api do - Ash.Actions.Helpers.add_process_context(opts[:api] || source.api, source, opts) + if api || source.api do + Ash.Actions.Helpers.add_process_context(api || source.api, source, opts) else {source, opts} end @@ -887,7 +891,7 @@ defmodule AshPhoenix.Form do forms: forms, form_keys: Keyword.new(List.wrap(opts[:forms])), id: id, - api: opts[:api], + api: api, method: opts[:method] || form_for_method(:create), opts: opts, touched_forms: touched_forms(forms, params, opts), @@ -1723,10 +1727,13 @@ defmodule AshPhoenix.Form do raise """ No Api configured, but one is required to submit the form. - For example: - + At form building: Form.for_create(Resource, :action, api: MyApp.MyApi) + + Or set up in the resource definition directly: + + use Ash.Resource, api: MyApp.MyApi """ end diff --git a/mix.exs b/mix.exs index c466b39..e8e3bd2 100644 --- a/mix.exs +++ b/mix.exs @@ -124,7 +124,7 @@ defmodule AshPhoenix.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:ash, ash_version("~> 2.14 and >= 2.14.1")}, + {:ash, ash_version("~> 2.16.1")}, {:phoenix, "~> 1.5.6 or ~> 1.6"}, {:phoenix_html, "~> 4.0"}, {:phoenix_live_view, "~> 0.20.3"}, diff --git a/mix.lock b/mix.lock index 60538ae..40a4bb3 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,5 @@ %{ - "ash": {:hex, :ash, "2.15.17", "253467af43c4febc8dfbd5f174c0725d1d2a86c6e7ba6d4dd04ff25936bbaaa6", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: false]}, {:plug, ">= 0.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:spark, ">= 1.1.20 and < 2.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:stream_data, "~> 0.6", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ea122915090b72c1fcff522bbf3cf566cc359479ae25de98e16509348d43430f"}, + "ash": {:hex, :ash, "2.16.1", "0c7f61275d9a30ab0c3d0fa68e51102227287d4c021351d3bd0fb1c6c456db98", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: false]}, {:plug, ">= 0.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:spark, ">= 1.1.50 and < 2.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:stream_data, "~> 0.6", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b6d3d2a419d6ca3041194caf6dab93dda2e759273ea0161942beace2b3441b7b"}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, "castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"}, "certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"}, @@ -9,8 +9,8 @@ "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, "earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"}, "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, - "ecto": {:hex, :ecto, "3.10.3", "eb2ae2eecd210b4eb8bece1217b297ad4ff824b4384c0e3fdd28aaf96edd6135", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "44bec74e2364d491d70f7e42cd0d690922659d329f6465e89feb8a34e8cd3433"}, - "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"}, + "ecto": {:hex, :ecto, "3.11.1", "4b4972b717e7ca83d30121b12998f5fcdc62ba0ed4f20fd390f16f3270d85c3e", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ebd3d3772cd0dfcd8d772659e41ed527c28b2a8bde4b00fe03e0463da0f1983b"}, + "elixir_make": {:hex, :elixir_make, "0.7.8", "505026f266552ee5aabca0b9f9c229cbb496c689537c9f922f3eb5431157efc7", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "7a71945b913d37ea89b06966e1342c85cfe549b15e6d6d081e8081c493062c07"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "ex_check": {:hex, :ex_check, "0.14.0", "d6fbe0bcc51cf38fea276f5bc2af0c9ae0a2bb059f602f8de88709421dae4f0e", [:mix], [], "hexpm", "8a602e98c66e6a4be3a639321f1f545292042f290f91fa942a285888c6868af0"}, @@ -28,7 +28,7 @@ "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, - "nimble_options": {:hex, :nimble_options, "1.0.2", "92098a74df0072ff37d0c12ace58574d26880e522c22801437151a159392270e", [:mix], [], "hexpm", "fd12a8db2021036ce12a309f26f564ec367373265b53e25403f0ee697380f1b8"}, + "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "phoenix": {:hex, :phoenix, "1.7.10", "02189140a61b2ce85bb633a9b6fd02dff705a5f1596869547aeb2b2b95edd729", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "cf784932e010fd736d656d7fead6a584a4498efefe5b8227e9f383bf15bb79d0"}, @@ -40,8 +40,8 @@ "plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"}, "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, "sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"}, - "sourceror": {:hex, :sourceror, "0.14.0", "b6b8552d0240400d66b6f107c1bab7ac1726e998efc797f178b7b517e928e314", [:mix], [], "hexpm", "809c71270ad48092d40bbe251a133e49ae229433ce103f762a2373b7a10a8d8b"}, - "spark": {:hex, :spark, "1.1.46", "ef554d17c41d6e7d3e116c635250653e80a1d7e3525039d8d16708ceec124521", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.1", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "ff039c2bc167946dae7369f321d6c8246f95e8221b307fb0a278b602a370f32f"}, + "sourceror": {:hex, :sourceror, "0.14.1", "c6fb848d55bd34362880da671debc56e77fd722fa13b4dcbeac89a8998fc8b09", [:mix], [], "hexpm", "8b488a219e4c4d7d9ff29d16346fd4a5858085ccdd010e509101e226bbfd8efc"}, + "spark": {:hex, :spark, "1.1.54", "54dac39403a2960f738ba5d60678d20b30de7381fb51b787b6bcb6aeabb73d9d", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.1", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "abc9a67cfb60a97d2f3c7e270fa968a2ace94f389e2741d406239d237ec6dbb1"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "stream_data": {:hex, :stream_data, "0.6.0", "e87a9a79d7ec23d10ff83eb025141ef4915eeb09d4491f79e52f2562b73e5f47", [:mix], [], "hexpm", "b92b5031b650ca480ced047578f1d57ea6dd563f5b57464ad274718c9c29501c"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, diff --git a/test/form_test.exs b/test/form_test.exs index e9f6fbd..e45cb9d 100644 --- a/test/form_test.exs +++ b/test/form_test.exs @@ -3,7 +3,7 @@ defmodule AshPhoenix.FormTest do import ExUnit.CaptureLog alias AshPhoenix.Form - alias AshPhoenix.Test.{Api, Author, Comment, OtherApi, Post, PostWithDefault} + alias AshPhoenix.Test.{Api, Artist, Author, Comment, OtherApi, Post, PostWithDefault} alias Phoenix.HTML.FormData defp form_for(form, _) do @@ -1011,6 +1011,37 @@ defmodule AshPhoenix.FormTest do |> Form.submit() end + test "it fallback to resource defined Api if unset" do + assert {:ok, %{name: "name"}} = + Artist + |> Form.for_action(:create) + |> Form.validate(%{name: "name"}) + |> Form.submit() + + assert {:ok, [%{name: "name"}]} = + Artist + |> Form.for_action(:read) + |> Form.validate(%{name: "name changed"}) + |> Form.submit() + + artist = + Artist + |> Ash.Changeset.new(%{name: "name"}) + |> Api.create!() + + assert {:ok, %{name: "name changed"}} = + artist + |> Form.for_action(:update) + |> Form.validate(%{name: "name changed"}) + |> Form.submit() + + assert :ok = + artist + |> Form.for_action(:destroy) + |> Form.validate(%{name: "name changed"}) + |> Form.submit() + end + test "it raises an appropriate error when the incorrect api is configured" do assert_raise Ash.Error.Invalid.ResourceNotAllowed, ~r/Resource `AshPhoenix.Test.Post` is not accepted by AshPhoenix.Test.OtherApi/, diff --git a/test/support/registry.ex b/test/support/registry.ex index a0135f4..fc47620 100644 --- a/test/support/registry.ex +++ b/test/support/registry.ex @@ -3,6 +3,7 @@ defmodule AshPhoenix.Test.Registry do use Ash.Registry entries do + entry(AshPhoenix.Test.Artist) entry(AshPhoenix.Test.Author) entry(AshPhoenix.Test.Comment) entry(AshPhoenix.Test.Post) diff --git a/test/support/resources/artist.ex b/test/support/resources/artist.ex new file mode 100644 index 0000000..f8b8c0d --- /dev/null +++ b/test/support/resources/artist.ex @@ -0,0 +1,20 @@ +defmodule AshPhoenix.Test.Artist do + @moduledoc false + + use Ash.Resource, + api: AshPhoenix.Test.Api, + data_layer: Ash.DataLayer.Ets + + ets do + private? true + end + + attributes do + uuid_primary_key :id + attribute :name, :string, allow_nil?: false + end + + actions do + defaults [:create, :read, :update, :destroy] + end +end