Skip to content

Instantly share code, notes, and snippets.

@nallwhy
Created April 30, 2024 08:07
Show Gist options
  • Save nallwhy/5691a136817b58f0f63b5f75860d2a0f to your computer and use it in GitHub Desktop.
Save nallwhy/5691a136817b58f0f63b5f75860d2a0f to your computer and use it in GitHub Desktop.
embedded in union type
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 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 TaskRequest do
use Ash.Resource, data_layer: :embedded
attributes do
attribute :todo_list, {:array, Todo}, allow_nil?: false
end
actions do
defaults [:read, create: [:todo_list], update: [:todo_list]]
end
end
defmodule Content do
use Ash.Type.NewType,
subtype_of: :union,
constraints: [
types: [
task_request: [
type: TaskRequest,
tag: :type,
tag_value: :task_request
]
]
]
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
form =
Post
|> AshPhoenix.Form.for_create(:create, forms: [auto?: true])
|> to_form()
|> AshPhoenix.Form.add_form(:content,
params: %{"type" => "task_request", "todo_list" => [%{}]}
)
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} />
<.inputs_for :let={fct} field={fc[:todo_list]}>
<label for={fct[:body].name}>body</label>
<input type="text" id={fct[:body].id} name={fct[:body].name} value={fct[:body].value} />
</.inputs_for>
</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