Skip to content

Commit 9183e0b

Browse files
aVikingTrexTrent Graw
andauthored
improvement: Add multitenancy to and create consistency between gen.html and gen.live (#459)
This deals with adding multitenancy (#310) to the generators. This also makes the prompts (named actor/multitenancy/use actor) consistent between the generators. --------- Co-authored-by: Trent Graw <candles-ultras.94@icloud.com>
1 parent 9064c5b commit 9183e0b

File tree

10 files changed

+1243
-76
lines changed

10 files changed

+1243
-76
lines changed

lib/ash_phoenix/gen/gen.ex

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ defmodule AshPhoenix.Gen do
4343
resource_plural: :string,
4444
resource_plural_for_routes: :string,
4545
actor: :string,
46-
no_actor: :boolean
46+
no_actor: :boolean,
47+
scope: :boolean,
48+
tenant: :string,
49+
no_tenant: :boolean
4750
]
4851
)
4952

@@ -56,6 +59,82 @@ defmodule AshPhoenix.Gen do
5659
{domain, resource, parsed, rest}
5760
end
5861

62+
def prompt_for_multitenancy(opts) do
63+
cond do
64+
opts[:scope] ->
65+
opts
66+
67+
opts[:no_actor] ->
68+
Keyword.put(opts, :actor, nil)
69+
70+
opts[:actor] || opts[:tenant] ->
71+
opts
72+
73+
true ->
74+
if Mix.shell().yes?("Are you using multi-tenancy?") do
75+
if Mix.shell().yes?(
76+
"Would you like to use scope, or separate actor and tenant? Choose yes for scope, no for separate actor and tenant."
77+
) do
78+
Keyword.put(opts, :scope, true)
79+
else
80+
opts = prompt_for_actor(opts)
81+
prompt_for_tenant(opts)
82+
end
83+
else
84+
prompt_for_actor(opts)
85+
end
86+
end
87+
end
88+
89+
def prompt_for_actor(opts) do
90+
if Mix.shell().yes?(
91+
"Would you like to name your actor? For example: `current_user`. If you choose no, we will not add any actor logic."
92+
) do
93+
actor =
94+
Mix.shell().prompt("What would you like to name it? Default: `current_user`")
95+
|> String.trim()
96+
97+
if actor == "" do
98+
Keyword.put(opts, :actor, "current_user")
99+
else
100+
Keyword.put(opts, :actor, actor)
101+
end
102+
else
103+
opts
104+
end
105+
end
106+
107+
def prompt_for_tenant(opts) do
108+
tenant =
109+
Mix.shell().prompt("What would you like to name your tenant? Default: `current_tenant`")
110+
|> String.trim()
111+
112+
if tenant == "" do
113+
Keyword.put(opts, :tenant, "current_tenant")
114+
else
115+
Keyword.put(opts, :tenant, tenant)
116+
end
117+
end
118+
119+
def actor_opt(opts, assigns_source) do
120+
cond do
121+
opts[:scope] ->
122+
", scope: #{assigns_source}.scope"
123+
124+
opts[:actor] && opts[:tenant] ->
125+
", actor: #{assigns_source}.#{opts[:actor]}, tenant: #{assigns_source}.#{opts[:tenant]}"
126+
127+
opts[:actor] ->
128+
", actor: #{assigns_source}.#{opts[:actor]}"
129+
130+
opts[:tenant] ->
131+
", tenant: #{assigns_source}.#{opts[:tenant]}"
132+
133+
true ->
134+
""
135+
end
136+
end
137+
59138
defp plural_name!(resource, opts) do
60139
plural_name =
61140
opts[:resource_plural] ||

lib/ash_phoenix/gen/live.ex

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,8 @@ if Code.ensure_loaded?(Igniter) do
3333
Code.ensure_compiled!(resource)
3434

3535
opts =
36-
if !opts[:actor] && opts[:interactive?] && !opts[:no_actor] do
37-
if Mix.shell().yes?(
38-
"Would you like to name your actor? For example: `current_user`. If you choose no, we will not add any actor logic."
39-
) do
40-
actor =
41-
Mix.shell().prompt("What would you like to name it? Default: `current_user`")
42-
|> String.trim()
43-
44-
if actor == "" do
45-
Keyword.put(opts, :actor, "current_user")
46-
else
47-
Keyword.put(opts, :actor, actor)
48-
end
49-
else
50-
opts
51-
end
36+
if opts[:interactive?] do
37+
AshPhoenix.Gen.prompt_for_multitenancy(opts)
5238
else
5339
opts
5440
end
@@ -74,7 +60,9 @@ if Code.ensure_loaded?(Igniter) do
7460
resource: inspect(resource),
7561
web_module: inspect(web_module(igniter)),
7662
actor: opts[:actor],
77-
actor_opt: actor_opt(opts)
63+
scope: opts[:scope],
64+
tenant: opts[:tenant],
65+
actor_opt: AshPhoenix.Gen.actor_opt(opts, "socket.assigns")
7866
]
7967
|> add_resource_assigns(resource, opts)
8068

@@ -296,13 +284,13 @@ if Code.ensure_loaded?(Igniter) do
296284
nil ->
297285
"""
298286
#{short_name} = #{get_by_pkey}
299-
Ash.destroy!(#{short_name}#{actor_opt(opts)})
287+
Ash.destroy!(#{short_name}#{AshPhoenix.Gen.actor_opt(opts, "socket.assigns")})
300288
"""
301289

302290
interface ->
303291
"""
304292
#{short_name} = #{get_by_pkey}
305-
#{inspect(resource)}.#{interface.name}!(#{short_name}#{actor_opt(opts)})
293+
#{inspect(resource)}.#{interface.name}!(#{short_name}#{AshPhoenix.Gen.actor_opt(opts, "socket.assigns")})
306294
"""
307295
end
308296
end
@@ -316,18 +304,10 @@ if Code.ensure_loaded?(Igniter) do
316304
end)
317305
|> case do
318306
nil ->
319-
"Ash.get!(#{inspect(resource)}, #{pkey}#{actor_opt(opts)})"
307+
"Ash.get!(#{inspect(resource)}, #{pkey}#{AshPhoenix.Gen.actor_opt(opts, "socket.assigns")})"
320308

321309
interface ->
322-
"#{inspect(resource)}.#{interface.name}!(#{pkey}#{actor_opt(opts)})"
323-
end
324-
end
325-
326-
defp actor_opt(opts) do
327-
if opts[:actor] do
328-
", actor: socket.assigns.#{opts[:actor]}"
329-
else
330-
""
310+
"#{inspect(resource)}.#{interface.name}!(#{pkey}#{AshPhoenix.Gen.actor_opt(opts, "socket.assigns")})"
331311
end
332312
end
333313

lib/mix/tasks/ash_phoenix.gen.html.ex

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ defmodule Mix.Tasks.AshPhoenix.Gen.Html do
3131
not_umbrella!()
3232
Mix.Task.run("compile")
3333

34-
{domain, resource, opts, _} = AshPhoenix.Gen.parse_opts(args)
34+
{domain, resource, parsed_opts, _} = AshPhoenix.Gen.parse_opts(args)
35+
36+
parsed_opts = AshPhoenix.Gen.prompt_for_multitenancy(parsed_opts)
3537

3638
singular = to_string(Ash.Resource.Info.short_name(resource))
3739

@@ -40,8 +42,13 @@ defmodule Mix.Tasks.AshPhoenix.Gen.Html do
4042
full_resource: resource,
4143
full_domain: domain,
4244
singular: singular,
43-
plural: opts[:resource_plural],
44-
plural_for_routes: opts[:resource_plural_for_routes] || opts[:resource_plural]
45+
plural: parsed_opts[:resource_plural],
46+
plural_for_routes:
47+
parsed_opts[:resource_plural_for_routes] || parsed_opts[:resource_plural],
48+
actor: parsed_opts[:actor],
49+
scope: parsed_opts[:scope],
50+
tenant: parsed_opts[:tenant],
51+
actor_opt: AshPhoenix.Gen.actor_opt(parsed_opts, "conn.assigns")
4552
}
4653

4754
if Code.ensure_loaded?(resource) do
@@ -80,6 +87,7 @@ defmodule Mix.Tasks.AshPhoenix.Gen.Html do
8087
|> Keyword.merge(
8188
route_prefix: to_string(opts[:plural_for_routes]),
8289
app_name: app_name(),
90+
actor_opt: opts[:actor_opt] || "",
8391
attributes: attributes(resource),
8492
update_attributes: update_attributes(resource),
8593
create_attributes: create_attributes(resource)

lib/mix/tasks/ash_phoenix.gen.live.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ if Code.ensure_loaded?(Igniter) do
4242
resourceplural: :string,
4343
resource_plural: :string,
4444
resource_plural_for_routes: :string,
45+
scope: :boolean,
46+
tenant: :string,
47+
no_tenant: :boolean,
4548
phx_version: :string
4649
],
4750
# Default values for the options in the `schema`.

priv/templates/ash_phoenix.gen.html/controller.ex.eex

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@ defmodule <%= @app_name %>Web.<%= @resource %>Controller do
44
alias <%= inspect @full_resource %>
55

66
def index(conn, _params) do
7-
<%= @plural %> = Ash.read!(<%= @resource %>)
7+
<%= @plural %> = Ash.read!(<%= @resource %><%= @actor_opt %>)
88
render(conn, :index, <%= @plural %>: <%= @plural %>)
99
end
1010

1111
def new(conn, _params) do
12-
render(conn, :new, form: create_form())
12+
render(conn, :new, form: create_form(conn))
1313
end
1414

1515
def create(conn, %{"<%= @singular %>" => <%= @singular %>_params}) do
1616
<%= @singular %>_params
17-
|> create_form()
17+
|> create_form(conn)
1818
|> AshPhoenix.Form.submit()
1919
|> case do
2020
{:ok, <%= @singular %>} ->
@@ -30,21 +30,21 @@ defmodule <%= @app_name %>Web.<%= @resource %>Controller do
3030
end
3131

3232
def show(conn, %{"id" => id}) do
33-
<%= @singular %> = Ash.get!(<%= @resource %>, id)
33+
<%= @singular %> = Ash.get!(<%= @resource %>, id<%= @actor_opt %>)
3434
render(conn, :show, <%= @singular %>: <%= @singular %>)
3535
end
3636

3737
def edit(conn, %{"id" => id}) do
38-
<%= @singular %> = Ash.get!(<%= @resource %>, id)
38+
<%= @singular %> = Ash.get!(<%= @resource %>, id<%= @actor_opt %>)
3939

40-
render(conn, :edit, <%= @singular %>: <%= @singular %>, form: update_form(<%= @singular %>))
40+
render(conn, :edit, <%= @singular %>: <%= @singular %>, form: update_form(conn, <%= @singular %>))
4141
end
4242

4343
def update(conn, %{"<%= @singular %>" => <%= @singular %>_params, "id" => id}) do
44-
<%= @singular %> = Ash.get!(<%= @resource %>, id)
44+
<%= @singular %> = Ash.get!(<%= @resource %>, id<%= @actor_opt %>)
4545

4646
<%= @singular %>
47-
|> update_form(<%= @singular %>_params)
47+
|> update_form(conn, <%= @singular %>_params)
4848
|> AshPhoenix.Form.submit()
4949
|> case do
5050
{:ok, <%= @singular %>} ->
@@ -60,19 +60,19 @@ defmodule <%= @app_name %>Web.<%= @resource %>Controller do
6060
end
6161

6262
def delete(conn, %{"id" => id}) do
63-
<%= @singular %> = Ash.get!(<%= @resource %>, id)
64-
Ash.destroy!(<%= @singular %>)
63+
<%= @singular %> = Ash.get!(<%= @resource %>, id<%= @actor_opt %>)
64+
Ash.destroy!(<%= @singular %><%= @actor_opt %>)
6565

6666
conn
6767
|> put_flash(:info, "<%= @resource %> deleted successfully.")
6868
|> redirect(to: ~p"/<%= @plural %>")
6969
end
7070

71-
defp create_form(params \\ nil) do
72-
AshPhoenix.Form.for_create(<%= @resource %>, :create, as: "<%= @singular %>", params: params)
71+
defp create_form(conn, params \\ nil) do
72+
AshPhoenix.Form.for_create(<%= @resource %>, :create, as: "<%= @singular %>", params: params<%= @actor_opt %>)
7373
end
7474

75-
defp update_form(<%= @singular %>, params \\ nil) do
76-
AshPhoenix.Form.for_update(<%= @singular %>, :update, as: "<%= @singular %>", params: params)
75+
defp update_form(conn, <%= @singular %>, params \\ nil) do
76+
AshPhoenix.Form.for_update(<%= @singular %>, :update, as: "<%= @singular %>", params: params<%= @actor_opt %>)
7777
end
7878
end

priv/templates/ash_phoenix.gen.live/new/index.ex.eex

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,20 @@ defmodule <%= inspect Module.concat(@web_module, @resource_alias) %>Live.Index d
5252
{:ok,
5353
socket
5454
|> assign(:page_title, "Listing <%= @resource_human_plural %>")
55-
<%= if @actor do %>
55+
<%= cond do %>
56+
<% @scope -> %>
57+
|> stream(:<%= @resource_plural %>, Ash.read!(<%= @resource %>, scope: socket.assigns.scope))}
58+
<% @actor && @tenant -> %>
59+
|> assign_new(:<%= @actor %>, fn -> nil end)
60+
|> assign_new(:<%= @tenant %>, fn -> nil end)
61+
|> stream(:<%= @resource_plural %>, Ash.read!(<%= @resource %>, actor: socket.assigns[:<%= @actor %>], tenant: socket.assigns[:<%= @tenant %>]))}
62+
<% @actor -> %>
5663
|> assign_new(:<%= @actor %>, fn -> nil end)
5764
|> stream(:<%= @resource_plural %>, Ash.read!(<%= @resource %>, actor: socket.assigns[:<%= @actor %>]))}
58-
<% else %>
65+
<% @tenant -> %>
66+
|> assign_new(:<%= @tenant %>, fn -> nil end)
67+
|> stream(:<%= @resource_plural %>, Ash.read!(<%= @resource %>, tenant: socket.assigns[:<%= @tenant %>]))}
68+
<% true -> %>
5969
|> stream(:<%= @resource_plural %>, Ash.read!(<%= @resource %>))}
6070
<% end %>
6171
end

0 commit comments

Comments
 (0)