Skip to content

Commit

Permalink
support --primary-key in phx.gen.{html,json,live} (#6096)
Browse files Browse the repository at this point in the history
Follow-up for #5766.
  • Loading branch information
SteffenDE authored Feb 20, 2025
1 parent e3103e8 commit 95c653f
Show file tree
Hide file tree
Showing 24 changed files with 139 additions and 60 deletions.
2 changes: 1 addition & 1 deletion lib/mix/tasks/phx.gen.context.ex
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ defmodule Mix.Tasks.Phx.Gen.Context do
end

{context, schema} = build(args)
binding = [context: context, schema: schema]
binding = [context: context, schema: schema, primary_key: schema.opts[:primary_key] || :id]
paths = Mix.Phoenix.generator_paths()

prompt_for_conflicts(context)
Expand Down
12 changes: 9 additions & 3 deletions lib/mix/tasks/phx.gen.html.ex
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,13 @@ defmodule Mix.Tasks.Phx.Gen.Html do
{context, schema} = Gen.Context.build(args)
Gen.Context.prompt_for_code_injection(context)

binding = [context: context, schema: schema, inputs: inputs(schema)]
binding = [
context: context,
schema: schema,
inputs: inputs(schema),
primary_key: schema.opts[:primary_key] || :id
]

paths = Mix.Phoenix.generator_paths()

prompt_for_conflicts(context)
Expand Down Expand Up @@ -173,15 +179,15 @@ defmodule Mix.Tasks.Phx.Gen.Html do
scope "/#{schema.web_path}", #{inspect(Module.concat(context.web_module, schema.web_namespace))}, as: :#{schema.web_path} do
pipe_through :browser
...
resources "/#{schema.plural}", #{inspect(schema.alias)}Controller
resources "/#{schema.plural}", #{inspect(schema.alias)}Controller#{if schema.opts[:primary_key], do: ~s[, param: "#{schema.opts[:primary_key]}"]}
end
""")
else
Mix.shell().info("""
Add the resource to your browser scope in #{Mix.Phoenix.web_path(ctx_app)}/router.ex:
resources "/#{schema.plural}", #{inspect(schema.alias)}Controller
resources "/#{schema.plural}", #{inspect(schema.alias)}Controller#{if schema.opts[:primary_key], do: ~s[, param: "#{schema.opts[:primary_key]}"]}
""")
end

Expand Down
7 changes: 4 additions & 3 deletions lib/mix/tasks/phx.gen.json.ex
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ defmodule Mix.Tasks.Phx.Gen.Json do
context: context,
schema: schema,
core_components?: Code.ensure_loaded?(Module.concat(context.web_module, "CoreComponents")),
gettext?: Code.ensure_loaded?(Module.concat(context.web_module, "Gettext"))
gettext?: Code.ensure_loaded?(Module.concat(context.web_module, "Gettext")),
primary_key: schema.opts[:primary_key] || :id
]

paths = Mix.Phoenix.generator_paths()
Expand Down Expand Up @@ -171,15 +172,15 @@ defmodule Mix.Tasks.Phx.Gen.Json do
scope "/#{schema.web_path}", #{inspect(Module.concat(context.web_module, schema.web_namespace))}, as: :#{schema.web_path} do
pipe_through :api
...
resources "/#{schema.plural}", #{inspect(schema.alias)}Controller
resources "/#{schema.plural}", #{inspect(schema.alias)}Controller#{if schema.opts[:primary_key], do: ~s[, param: "#{schema.opts[:primary_key]}"]}
end
""")
else
Mix.shell().info("""
Add the resource to the "#{Application.get_env(ctx_app, :generators)[:api_prefix] || "/api"}" scope in #{Mix.Phoenix.web_path(ctx_app)}/router.ex:
resources "/#{schema.plural}", #{inspect(schema.alias)}Controller, except: [:new, :edit]
resources "/#{schema.plural}", #{inspect(schema.alias)}Controller, except: [:new, :edit]#{if schema.opts[:primary_key], do: ~s[, param: "#{schema.opts[:primary_key]}"]}
""")
end

Expand Down
16 changes: 12 additions & 4 deletions lib/mix/tasks/phx.gen.live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,13 @@ defmodule Mix.Tasks.Phx.Gen.Live do

Gen.Context.prompt_for_code_injection(context)

binding = [context: context, schema: schema, inputs: inputs(schema)]
binding = [
context: context,
schema: schema,
inputs: inputs(schema),
primary_key: schema.opts[:primary_key] || :id
]

paths = Mix.Phoenix.generator_paths()

prompt_for_conflicts(context)
Expand All @@ -134,7 +140,9 @@ defmodule Mix.Tasks.Phx.Gen.Live do
defp validate_context!(context) do
cond do
context.schema.singular == "form" ->
Gen.Context.raise_with_help("cannot use form as the schema name because it conflicts with the LiveView assigns!")
Gen.Context.raise_with_help(
"cannot use form as the schema name because it conflicts with the LiveView assigns!"
)

true ->
:ok
Expand Down Expand Up @@ -281,8 +289,8 @@ defmodule Mix.Tasks.Phx.Gen.Live do
[
~s|live "/#{schema.plural}", #{inspect(schema.alias)}Live.Index, :index\n|,
~s|live "/#{schema.plural}/new", #{inspect(schema.alias)}Live.Form, :new\n|,
~s|live "/#{schema.plural}/:id", #{inspect(schema.alias)}Live.Show, :show\n|,
~s|live "/#{schema.plural}/:id/edit", #{inspect(schema.alias)}Live.Form, :edit|
~s|live "/#{schema.plural}/:#{schema.opts[:primary_key] || :id}", #{inspect(schema.alias)}Live.Show, :show\n|,
~s|live "/#{schema.plural}/:#{schema.opts[:primary_key] || :id}/edit", #{inspect(schema.alias)}Live.Form, :edit|
]
end

Expand Down
2 changes: 1 addition & 1 deletion lib/mix/tasks/phx.gen.schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ defmodule Mix.Tasks.Phx.Gen.Schema do
prompt_for_conflicts(schema)

schema
|> copy_new_files(paths, schema: schema)
|> copy_new_files(paths, schema: schema, primary_key: schema.opts[:primary_key] || :id)
|> print_shell_instructions()
end

Expand Down
2 changes: 1 addition & 1 deletion priv/templates/phx.gen.context/access_no_schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
%<%= inspect schema.alias %>{}
"""
def get_<%= schema.singular %>!(id), do: raise "TODO"
def get_<%= schema.singular %>!(<%= primary_key %>), do: raise "TODO"

@doc """
Creates a <%= schema.singular %>.
Expand Down
2 changes: 1 addition & 1 deletion priv/templates/phx.gen.context/schema_access.ex
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
** (Ecto.NoResultsError)
"""
def get_<%= schema.singular %>!(id), do: Repo.get!(<%= inspect schema.alias %>, id)
def get_<%= schema.singular %>!(<%= primary_key %>), do: Repo.get!(<%= inspect schema.alias %>, <%= primary_key %>)

@doc """
Creates a <%= schema.singular %>.
Expand Down
6 changes: 3 additions & 3 deletions priv/templates/phx.gen.context/test_cases.exs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

test "get_<%= schema.singular %>!/1 returns the <%= schema.singular %> with given id" do
<%= schema.singular %> = <%= schema.singular %>_fixture()
assert <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= schema.singular %>.<%= schema.opts[:primary_key] || :id %>) == <%= schema.singular %>
assert <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= schema.singular %>.<%= primary_key %>) == <%= schema.singular %>
end

test "create_<%= schema.singular %>/1 with valid data creates a <%= schema.singular %>" do
Expand All @@ -38,13 +38,13 @@
test "update_<%= schema.singular %>/2 with invalid data returns error changeset" do
<%= schema.singular %> = <%= schema.singular %>_fixture()
assert {:error, %Ecto.Changeset{}} = <%= inspect context.alias %>.update_<%= schema.singular %>(<%= schema.singular %>, @invalid_attrs)
assert <%= schema.singular %> == <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= schema.singular %>.<%= schema.opts[:primary_key] || :id %>)
assert <%= schema.singular %> == <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= schema.singular %>.<%= primary_key %>)
end

test "delete_<%= schema.singular %>/1 deletes the <%= schema.singular %>" do
<%= schema.singular %> = <%= schema.singular %>_fixture()
assert {:ok, %<%= inspect schema.alias %>{}} = <%= inspect context.alias %>.delete_<%= schema.singular %>(<%= schema.singular %>)
assert_raise Ecto.NoResultsError, fn -> <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= schema.singular %>.<%= schema.opts[:primary_key] || :id %>) end
assert_raise Ecto.NoResultsError, fn -> <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= schema.singular %>.<%= primary_key %>) end
end

test "change_<%= schema.singular %>/1 returns a <%= schema.singular %> changeset" do
Expand Down
16 changes: 8 additions & 8 deletions priv/templates/phx.gen.html/controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
end
end
def show(conn, %{"id" => id}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id)
def show(conn, %{"<%= primary_key %>" => <%= primary_key %>}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= primary_key %>)
render(conn, :show, <%= schema.singular %>: <%= schema.singular %>)
end
def edit(conn, %{"id" => id}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id)
def edit(conn, %{"<%= primary_key %>" => <%= primary_key %>}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= primary_key %>)
changeset = <%= inspect context.alias %>.change_<%= schema.singular %>(<%= schema.singular %>)
render(conn, :edit, <%= schema.singular %>: <%= schema.singular %>, changeset: changeset)
end
def update(conn, %{"id" => id, <%= inspect schema.singular %> => <%= schema.singular %>_params}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id)
def update(conn, %{"<%= primary_key %>" => <%= primary_key %>, <%= inspect schema.singular %> => <%= schema.singular %>_params}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= primary_key %>)
case <%= inspect context.alias %>.update_<%= schema.singular %>(<%= schema.singular %>, <%= schema.singular %>_params) do
{:ok, <%= schema.singular %>} ->
Expand All @@ -51,8 +51,8 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
end
end

def delete(conn, %{"id" => id}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id)
def delete(conn, %{"<%= primary_key %>" => <%= primary_key %>}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= primary_key %>)
{:ok, _<%= schema.singular %>} = <%= inspect context.alias %>.delete_<%= schema.singular %>(<%= schema.singular %>)

conn
Expand Down
8 changes: 4 additions & 4 deletions priv/templates/phx.gen.html/controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
test "redirects to show when data is valid", %{conn: conn} do
conn = post(conn, ~p"<%= schema.route_prefix %>", <%= schema.singular %>: @create_attrs)

assert %{id: id} = redirected_params(conn)
assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/#{id}"
assert %{<%= primary_key %>: <%= primary_key %>} = redirected_params(conn)
assert redirected_to(conn) == ~p"<%= schema.route_prefix %>/#{<%= primary_key %>}"
conn = get(conn, ~p"<%= schema.route_prefix %>/#{id}")
assert html_response(conn, 200) =~ "<%= schema.human_singular %> #{id}"
conn = get(conn, ~p"<%= schema.route_prefix %>/#{<%= primary_key %>}")
assert html_response(conn, 200) =~ "<%= schema.human_singular %> #{<%= primary_key %>}"
end
test "renders errors when data is invalid", %{conn: conn} do
Expand Down
2 changes: 1 addition & 1 deletion priv/templates/phx.gen.html/edit.html.heex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<.header>
Edit <%= schema.human_singular %> {@<%= schema.singular %>.id}
Edit <%= schema.human_singular %> {@<%= schema.singular %>.<%= primary_key %>}
<:subtitle>Use this form to manage <%= schema.singular %> records in your database.</:subtitle>
</.header>

Expand Down
2 changes: 1 addition & 1 deletion priv/templates/phx.gen.html/show.html.heex
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<.header>
<%= schema.human_singular %> {@<%= schema.singular %>.id}
<%= schema.human_singular %> {@<%= schema.singular %>.<%= primary_key %>}
<:subtitle>This is a <%= schema.singular %> record from your database.</:subtitle>
<:actions>
<.link class={button_classes()} href={~p"<%= schema.route_prefix %>/#{@<%= schema.singular %>}/edit"}>
Expand Down
12 changes: 6 additions & 6 deletions priv/templates/phx.gen.json/controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,21 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
end
end
def show(conn, %{"id" => id}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id)
def show(conn, %{"<%= primary_key %>" => <%= primary_key %>}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= primary_key %>)
render(conn, :show, <%= schema.singular %>: <%= schema.singular %>)
end
def update(conn, %{"id" => id, <%= inspect schema.singular %> => <%= schema.singular %>_params}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id)
def update(conn, %{"<%= primary_key %>" => <%= primary_key %>, <%= inspect schema.singular %> => <%= schema.singular %>_params}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= primary_key %>)
with {:ok, %<%= inspect schema.alias %>{} = <%= schema.singular %>} <- <%= inspect context.alias %>.update_<%= schema.singular %>(<%= schema.singular %>, <%= schema.singular %>_params) do
render(conn, :show, <%= schema.singular %>: <%= schema.singular %>)
end
end
def delete(conn, %{"id" => id}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id)
def delete(conn, %{"<%= primary_key %>" => <%= primary_key %>}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= primary_key %>)
with {:ok, %<%= inspect schema.alias %>{}} <- <%= inspect context.alias %>.delete_<%= schema.singular %>(<%= schema.singular %>) do
send_resp(conn, :no_content, "")
Expand Down
14 changes: 7 additions & 7 deletions priv/templates/phx.gen.json/controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
describe "create <%= schema.singular %>" do
test "renders <%= schema.singular %> when data is valid", %{conn: conn} do
conn = post(conn, ~p"<%= schema.api_route_prefix %>", <%= schema.singular %>: @create_attrs)
assert %{"id" => id} = json_response(conn, 201)["data"]
assert %{"<%= primary_key %>" => <%= primary_key %>} = json_response(conn, 201)["data"]

conn = get(conn, ~p"<%= schema.api_route_prefix %>/#{id}")
conn = get(conn, ~p"<%= schema.api_route_prefix %>/#{<%= primary_key %>}")

assert %{
"id" => ^id<%= for {key, val} <- schema.params.create |> Phoenix.json_library().encode!() |> Phoenix.json_library().decode!() do %>,
"<%= primary_key %>" => ^<%= primary_key %><%= for {key, val} <- schema.params.create |> Phoenix.json_library().encode!() |> Phoenix.json_library().decode!() do %>,
"<%= key %>" => <%= inspect(val) %><% end %>
} = json_response(conn, 200)["data"]
end
Expand All @@ -46,14 +46,14 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
describe "update <%= schema.singular %>" do
setup [:create_<%= schema.singular %>]

test "renders <%= schema.singular %> when data is valid", %{conn: conn, <%= schema.singular %>: %<%= inspect schema.alias %>{id: id} = <%= schema.singular %>} do
test "renders <%= schema.singular %> when data is valid", %{conn: conn, <%= schema.singular %>: %<%= inspect schema.alias %>{<%= primary_key %>: <%= primary_key %>} = <%= schema.singular %>} do
conn = put(conn, ~p"<%= schema.api_route_prefix %>/#{<%= schema.singular %>}", <%= schema.singular %>: @update_attrs)
assert %{"id" => ^id} = json_response(conn, 200)["data"]
assert %{"<%= primary_key %>" => ^<%= primary_key %>} = json_response(conn, 200)["data"]
conn = get(conn, ~p"<%= schema.api_route_prefix %>/#{id}")
conn = get(conn, ~p"<%= schema.api_route_prefix %>/#{<%= primary_key %>}")

assert %{
"id" => ^id<%= for {key, val} <- schema.params.update |> Phoenix.json_library().encode!() |> Phoenix.json_library().decode!() do %>,
"<%= primary_key %>" => ^<%= primary_key %><%= for {key, val} <- schema.params.update |> Phoenix.json_library().encode!() |> Phoenix.json_library().decode!() do %>,
"<%= key %>" => <%= inspect(val) %><% end %>
} = json_response(conn, 200)["data"]
end
Expand Down
2 changes: 1 addition & 1 deletion priv/templates/phx.gen.json/json.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web

defp data(%<%= inspect schema.alias %>{} = <%= schema.singular %>) do
%{
<%= [{:id, :id} | schema.attrs] |> Enum.map(fn {k, _} -> " #{k}: #{schema.singular}.#{k}" end) |> Enum.join(",\n") %>
<%= [{primary_key, :id} | schema.attrs] |> Enum.map(fn {k, _} -> " #{k}: #{schema.singular}.#{k}" end) |> Enum.join(",\n") %>
}
end
end
4 changes: 2 additions & 2 deletions priv/templates/phx.gen.live/form.ex
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
defp return_to("show"), do: "show"
defp return_to(_), do: "index"

defp apply_action(socket, :edit, %{"id" => id}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id)
defp apply_action(socket, :edit, %{"<%= primary_key %>" => <%= primary_key %>}) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= primary_key %>)

socket
|> assign(:page_title, "Edit <%= schema.human_singular %>")
Expand Down
10 changes: 5 additions & 5 deletions priv/templates/phx.gen.live/index.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
</:action>
<:action :let={{id, <%= schema.singular %>}}>
<.link
phx-click={JS.push("delete", value: %{id: <%= schema.singular %>.<%= schema.opts[:primary_key] || :id %>}) |> hide("##{id}")}
phx-click={JS.push("delete", value: %{<%= primary_key %>: <%= schema.singular %>.<%= primary_key %>}) |> hide("##{id}")}
data-confirm="Are you sure?"
>
Delete
Expand All @@ -43,14 +43,14 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
def mount(_params, _session, socket) do
{:ok,
socket
|> assign(:page_title, "Listing <%= schema.human_plural %>")<%= if schema.opts[:primary_key] do %>
|> stream_configure(:<%= schema.collection %>, dom_id: &"<%= schema.table %>-#{&1.<%= schema.opts[:primary_key] %>}")<% end %>
|> assign(:page_title, "Listing <%= schema.human_plural %>")<%= if primary_key != :id do %>
|> stream_configure(:<%= schema.collection %>, dom_id: &"<%= schema.table %>-#{&1.<%= primary_key %>}")<% end %>
|> stream(:<%= schema.collection %>, <%= inspect context.alias %>.list_<%= schema.plural %>())}
end
@impl true
def handle_event("delete", %{"id" => id}, socket) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(id)
def handle_event("delete", %{"<%= primary_key %>" => <%= primary_key %>}, socket) do
<%= schema.singular %> = <%= inspect context.alias %>.get_<%= schema.singular %>!(<%= primary_key %>)
{:ok, _} = <%= inspect context.alias %>.delete_<%= schema.singular %>(<%= schema.singular %>)

{:noreply, stream_delete(socket, :<%= schema.collection %>, <%= schema.singular %>)}
Expand Down
6 changes: 3 additions & 3 deletions priv/templates/phx.gen.live/live_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web

assert {:ok, form_live, _html} =
index_live
|> element("#<%= schema.plural %>-#{<%= schema.singular %>.<%= schema.opts[:primary_key] || :id %>} a", "Edit")
|> element("#<%= schema.plural %>-#{<%= schema.singular %>.<%= primary_key %>} a", "Edit")
|> render_click()
|> follow_redirect(conn, ~p"<%= schema.route_prefix %>/#{<%= schema.singular %>}/edit")
Expand All @@ -78,8 +78,8 @@ defmodule <%= inspect context.web_module %>.<%= inspect Module.concat(schema.web
test "deletes <%= schema.singular %> in listing", %{conn: conn, <%= schema.singular %>: <%= schema.singular %>} do
{:ok, index_live, _html} = live(conn, ~p"<%= schema.route_prefix %>")

assert index_live |> element("#<%= schema.plural %>-#{<%= schema.singular %>.<%= schema.opts[:primary_key] || :id %>} a", "Delete") |> render_click()
refute has_element?(index_live, "#<%= schema.plural %>-#{<%= schema.singular %>.<%= schema.opts[:primary_key] || :id %>}")
assert index_live |> element("#<%= schema.plural %>-#{<%= schema.singular %>.<%= primary_key %>} a", "Delete") |> render_click()
refute has_element?(index_live, "#<%= schema.plural %>-#{<%= schema.singular %>.<%= primary_key %>}")
end
end

Expand Down
Loading

0 comments on commit 95c653f

Please sign in to comment.