Skip to content

Instantly share code, notes, and snippets.

@nallwhy
Created August 8, 2024 03:30
Show Gist options
  • Save nallwhy/18701d2a287309990e1596f262e9584d to your computer and use it in GitHub Desktop.
Save nallwhy/18701d2a287309990e1596f262e9584d to your computer and use it in GitHub Desktop.
Error with embedded array attribute on create
Application.put_env(:sample, SamplePhoenix.Endpoint,
http: [ip: {127, 0, 0, 1}, port: 5001],
server: true,
live_view: [signing_salt: "aaaaaaaa"],
secret_key_base: String.duplicate("a", 64)
)
Mix.install([
{:plug_cowboy, "~> 2.7"},
{:jason, "~> 1.0"},
{:phoenix, "1.7.12"},
{:phoenix_live_view, "0.20.14"},
# {:ash, "3.3.3"},
{:ash,
github: "ash-project/ash", ref: "4278660c9c937a87f6141167a237eb9aa5ac562c", override: true},
{:ash_phoenix, "2.1.1"}
])
defmodule SamplePhoenix.ErrorView do
def render(template, _), do: Phoenix.Controller.status_message_from_template(template)
end
defmodule Todo do
use Ash.Resource, data_layer: :embedded
attributes do
attribute :body, :string, allow_nil?: false
end
actions do
defaults [:read, create: [:body], update: [:body]]
end
end
defmodule Post do
use Ash.Resource, data_layer: Ash.DataLayer.Ets, domain: Domain
attributes do
uuid_primary_key :id
attribute :title, :string, allow_nil?: false
attribute :todo_list, {:array, Todo}, allow_nil?: false
end
actions do
defaults create: [:title, :todo_list], update: [:title, :todo_list]
end
end
defmodule Domain do
use Ash.Domain
resources do
resource Post
end
end
defmodule SamplePhoenix.SampleLive do
use Phoenix.LiveView, layout: {__MODULE__, :live}
def mount(_params, _session, socket) do
form =
Post
|> AshPhoenix.Form.for_create(:create, forms: [auto?: true])
|> to_form()
|> AshPhoenix.Form.add_form([:todo_list, 0])
socket =
socket
|> assign(form: form)
|> assign(result: nil)
{:ok, socket}
end
# layout
def render("live.html", assigns) do
~H"""
<script src="https://cdn.jsdelivr.net/npm/phoenix@1.7.12/priv/static/phoenix.min.js">
</script>
<script
src="https://cdn.jsdelivr.net/npm/phoenix_live_view@0.20.14/priv/static/phoenix_live_view.min.js"
>
</script>
<script>
let liveSocket = new window.LiveView.LiveSocket("/live", window.Phoenix.Socket)
liveSocket.connect()
</script>
<style>
* { font-size: 1.1em; }
</style>
<%= @inner_content %>
"""
end
# render
def render(assigns) do
~H"""
<.form id="form" for={@form} phx-change="validate" phx-submit="save">
<div>
<label for={@form[:title].name}>title</label>
<input
type="text"
id={@form[:title].id}
name={@form[:title].name}
value={@form[:title].value}
/>
</div>
<.inputs_for :let={ft} field={@form[:todo_list]}>
<label for={ft[:body].name}>body</label>
<input type="text" id={ft[:body].id} name={ft[:body].name} value={ft[:body].value} />
</.inputs_for>
<button type="submit" disabled={!@form.source.valid?}>Save</button>
</.form>
<div :if={@result}>
result: <%= inspect(@result) %>
</div>
form: <%= inspect(@form) %>
"""
end
def handle_event("validate", %{"form" => params}, socket) do
form = socket.assigns.form |> AshPhoenix.Form.validate(params)
socket =
socket
|> assign(form: form)
{:noreply, socket}
end
def handle_event("save", _params, socket) do
socket =
case socket.assigns.form |> AshPhoenix.Form.submit() do
{:ok, result} ->
socket |> assign(result: result)
{:error, form} ->
socket |> assign(form: form)
end
{:noreply, socket}
end
end
defmodule Router do
use Phoenix.Router
import Phoenix.LiveView.Router
pipeline :browser do
plug(:accepts, ["html"])
end
scope "/", SamplePhoenix do
pipe_through(:browser)
live("/", SampleLive, :index)
end
end
defmodule SamplePhoenix.Endpoint do
use Phoenix.Endpoint, otp_app: :sample
socket("/live", Phoenix.LiveView.Socket)
plug(Router)
end
{:ok, _} = Supervisor.start_link([SamplePhoenix.Endpoint], strategy: :one_for_one)
Process.sleep(:infinity)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment