Skip to content

Instantly share code, notes, and snippets.

@nallwhy
Created April 30, 2024 01:04
Show Gist options
  • Save nallwhy/bab128b393e4a1db5ae514ea06e57a31 to your computer and use it in GitHub Desktop.
Save nallwhy/bab128b393e4a1db5ae514ea06e57a31 to your computer and use it in GitHub Desktop.
union type not loaded
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.0.0-rc.36"},
{:ash_phoenix, "2.0.0-rc.8"}
])
defmodule SamplePhoenix.ErrorView do
def render(template, _), do: Phoenix.Controller.status_message_from_template(template)
end
defmodule NormalContent 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 Content do
use Ash.Type.NewType,
subtype_of: :union,
constraints: [
types: [
normal: [
type: NormalContent,
tag: :type,
tag_value: :normal
]
]
]
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 :content, Content, allow_nil?: false
end
actions do
defaults [create: [:title, :content], update: [:title, :content]]
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
mode = "update"
form =
case mode do
"create" ->
Post
|> AshPhoenix.Form.for_create(:create, forms: [auto?: true])
|> to_form()
|> AshPhoenix.Form.add_form(:content, params: %{"type" => "normal"})
"update" ->
post =
Post
|> Ash.Changeset.new()
|> Ash.Changeset.change_attributes(%{
title: "title",
content: %{"type" => "normal", "body" => "body"}
})
|> Ash.create!()
post
|> AshPhoenix.Form.for_update(:update, forms: [auto?: true])
|> to_form()
end
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={fc} field={@form[:content]}>
<div>
<input type="hidden" id={fc[:type].id} name={fc[:type].name} value={:normal} />
<label for={fc[:body].name}>body</label>
<input type="text" id={fc[:body].id} name={fc[:body].name} value={fc[:body].value} />
</div>
</.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