AF
Ash Framework•2mo ago
E

How to run custom resource extension before validators

Hi there, I'm writing my first Ash.Resource extension and having some issues I don't know how to solve. This is my simple extension so far:
defmodule EKG.Extensions.ScenePlaceable do
use Spark.Dsl.Extension, transformers: [EKG.Extensions.ScenePlaceable.AddAttributes]
end

defmodule EKG.Extensions.ScenePlaceable.AddAttributes do
use Spark.Dsl.Transformer

def transform(dsl_state) do
dsl_state
|> Ash.Resource.Builder.add_new_attribute(:x, :integer,
description: "X coordinate position",
allow_nil?: false,
public?: true,
constraints: [min: 0]
)
# ... other attrs
end
end
defmodule EKG.Extensions.ScenePlaceable do
use Spark.Dsl.Extension, transformers: [EKG.Extensions.ScenePlaceable.AddAttributes]
end

defmodule EKG.Extensions.ScenePlaceable.AddAttributes do
use Spark.Dsl.Transformer

def transform(dsl_state) do
dsl_state
|> Ash.Resource.Builder.add_new_attribute(:x, :integer,
description: "X coordinate position",
allow_nil?: false,
public?: true,
constraints: [min: 0]
)
# ... other attrs
end
end
All it does is add some attributes to the resource. But when I add EKG.Extensions.ScenePlaceable to the list of extensions of my resource I'm now getting this compile error:
== Compilation error in file lib/ekg/scenes/scene_widget.ex ==
** (Spark.Error.DslError) [EKG.Scenes.SceneWidget]
actions -> update -> accept:
Cannot accept [:x, :y, :width, :height, :z_index], because they are not attributes."
== Compilation error in file lib/ekg/scenes/scene_widget.ex ==
** (Spark.Error.DslError) [EKG.Scenes.SceneWidget]
actions -> update -> accept:
Cannot accept [:x, :y, :width, :height, :z_index], because they are not attributes."
So looks like that validation is running before my extension has a chance to add the attributes? As far as I'm aware the docs don't mention how to configure an extension to get around this issue, but I'm sure the fix is easy. Thank you for your help!
Solution:
You can do this in your transformer: ```elixir def before?(Ash.Resource.Transformers.DefaultAccept), do: true def before?(_), do: false...
Jump to solution
5 Replies
Solution
ZachDaniel
ZachDaniel•2mo ago
You can do this in your transformer:
def before?(Ash.Resource.Transformers.DefaultAccept), do: true
def before?(_), do: false
def before?(Ash.Resource.Transformers.DefaultAccept), do: true
def before?(_), do: false
ZachDaniel
ZachDaniel•2mo ago
its something I'd like to improve, but at the moment you basically have to know what thing produces the error and place yourself before/after it accordingly
E
EOP•2mo ago
Hmm, I tried adding that before (and just again to confirm) and I'm getting the error unfortunately Hmm, this may be due to how I'm also using a custom base resource...
defmodule EKG.Resource do
@default_options [
otp_app: :ekg,
data_layer: AshPostgres.DataLayer,
extensions: [AshPhoenix],
authorizers: [Ash.Policy.Authorizer],
notifiers: [Ash.Notifier.PubSub]
]

defmacro __using__(opts) do
merged_opts = Keyword.merge(@default_options, opts) |> dbg

quote do
use Ash.Resource, unquote(merged_opts)
end
end
end
defmodule EKG.Resource do
@default_options [
otp_app: :ekg,
data_layer: AshPostgres.DataLayer,
extensions: [AshPhoenix],
authorizers: [Ash.Policy.Authorizer],
notifiers: [Ash.Notifier.PubSub]
]

defmacro __using__(opts) do
merged_opts = Keyword.merge(@default_options, opts) |> dbg

quote do
use Ash.Resource, unquote(merged_opts)
end
end
end
I have a feeling the options I'm giving are not being merged in correctly
ZachDaniel
ZachDaniel•2mo ago
That should be fine 🤔 it could be a different transformer showing that error.
E
EOP•2mo ago
To follow up, the issue was with my custom resource. I had to update it to this:
defmodule EKG.Resource do
defmacro __using__(opts) do
quote do
use Ash.Resource, [
unquote_splicing(opts),
otp_app: :ekg,
data_layer: AshPostgres.DataLayer,
extensions: [AshPhoenix],
authorizers: [Ash.Policy.Authorizer],
notifiers: [Ash.Notifier.PubSub]
]
end
end
end
defmodule EKG.Resource do
defmacro __using__(opts) do
quote do
use Ash.Resource, [
unquote_splicing(opts),
otp_app: :ekg,
data_layer: AshPostgres.DataLayer,
extensions: [AshPhoenix],
authorizers: [Ash.Policy.Authorizer],
notifiers: [Ash.Notifier.PubSub]
]
end
end
end
TBH, I still don't really get Elixir macros and often just have to bumble around until something just works â„¢

Did you find this page helpful?