Repository: phoenixframework/phoenix
Pull request #4608 (2021-11-20 08:39:17)

Update contexts.md: create cart_item_controller.ex in right dir
create `cart_item_controller.ex` in right dir for consistency
from: `lib/hello_web/cart_item_controller.ex`
to: `lib/hello_web/controllers/cart_item_controller.ex`


Patch:
diff --git a/guides/contexts.md b/guides/contexts.md
index 673bfae1b..6a66cf364 100644
--- a/guides/contexts.md
+++ b/guides/contexts.md
@@ -262,7 +262,7 @@ Intuitively, you would assume the following events:
   1. User 1 loads the product page with count of 13
   2. User 1 saves the product page with count of 14
   3. User 2 loads the product page with count of 14
-  4. User 2 loads the product page with count of 15
+  4. User 2 saves the product page with count of 15
 
 While in practice this would happen:
 
@@ -273,7 +273,7 @@ While in practice this would happen:
 
 The race conditions would make this an unreliable way to update the existing table since multiple callers may be updating out of date view values. There's a better way.
 
-Let's think of a function describes what we want to accomplish. Here's how we would like to use it:
+Let's think of a function that describes what we want to accomplish. Here's how we would like to use it:
 
     product = Catalog.inc_page_views(product)
 
@@ -752,7 +752,7 @@ We added a new `:fetch_current_user` and `:fetch_current_cart` plug to our brows
 
 We'll need to implement a cart controller for handling cart operations like viewing a cart, updating quantities, and initiating the checkout process, as well as a cart items controller for adding and removing individual items to and from the cart. Add the following routes to your router in `lib/hello_web/router.ex`:
 
-```elixir
+```diff
   scope "/", HelloWeb do
     pipe_through :browser
 
@@ -768,7 +768,7 @@ We'll need to implement a cart controller for handling cart operations like view
 
 We added a `resources` declaration for a `CartItemController`, which will wire up the routes for a create and delete action for adding and remove individual cart items. Next, we added two new routes pointing at a `CartController`. The first route, a GET request, will map to our show action, to show the cart contents. The second route, a PUT request, will handle the submission of a form for updating our cart quantities.
 
-With our routes in place, let's add the ability to add an item to our cart from the product show page. Create a new file at `lib/hello_web/cart_item_controller.ex` and key this in:
+With our routes in place, let's add the ability to add an item to our cart from the product show page. Create a new file at `lib/hello_web/controllers/cart_item_controller.ex` and key this in:
 
 ```elixir
 defmodule HelloWeb.CartItemController do
diff --git a/guides/controllers.md b/guides/controllers.md
index 0a69a443b..089283be7 100644
--- a/guides/controllers.md
+++ b/guides/controllers.md
@@ -262,9 +262,10 @@ def index(conn, _params) do
 end
 ```
 
-Reloading [http://localhost:4000](http://localhost:4000) should show us a completely blank page. The network tab of our browser's developer tools should show a response status of "201" (Created).
+Reloading [http://localhost:4000](http://localhost:4000) should show us a completely blank page. The network tab of our browser's developer tools should show a response status of "201" (Created). Some browsers (Safari) will download the response, as the content type is not set.
+
+To be specific about the content type, we can use [`put_resp_content_type/2`] in conjunction with [`send_resp/3`].
 
-If we would like to be really specific about the content type, we can use [`put_resp_content_type/2`] in conjunction with [`send_resp/3`].
 
 ```elixir
 def index(conn, _params) do
diff --git a/lib/mix/phoenix/schema.ex b/lib/mix/phoenix/schema.ex
index 571ee90d4..4b2004b21 100644
--- a/lib/mix/phoenix/schema.ex
+++ b/lib/mix/phoenix/schema.ex
@@ -255,6 +255,12 @@ defmodule Mix.Phoenix.Schema do
   def type_for_migration({:enum, _}), do: :string
   def type_for_migration(other), do: other
 
+  def format_fields_for_schema(schema) do
+    Enum.map_join(schema.types, "\n", fn {k, v} ->
+      "    field #{inspect(k)}, #{type_and_opts_for_schema(v)}#{schema.defaults[k]}#{maybe_redact_field(k in schema.redacts)}"
+    end)
+  end
+
   def type_and_opts_for_schema({:enum, opts}), do: ~s|Ecto.Enum, values: #{inspect Keyword.get(opts, :values)}|
   def type_and_opts_for_schema(other), do: inspect other
 
diff --git a/lib/mix/tasks/phx.gen.auth.ex b/lib/mix/tasks/phx.gen.auth.ex
index a8f8c7ada..386961bfd 100644
--- a/lib/mix/tasks/phx.gen.auth.ex
+++ b/lib/mix/tasks/phx.gen.auth.ex
@@ -524,7 +524,7 @@ defmodule Mix.Tasks.Phx.Gen.Auth do
         $ mix ecto.migrate
 
     Once you are ready, visit "/#{context.schema.plural}/register"
-    to create your account and then access to "/dev/mailbox" to
+    to create your account and then access "/dev/mailbox" to
     see the account confirmation email.
     """)
 
diff --git a/priv/templates/phx.gen.embedded/embedded_schema.ex b/priv/templates/phx.gen.embedded/embedded_schema.ex
index 03c4b6fd1..e3acfb81a 100644
--- a/priv/templates/phx.gen.embedded/embedded_schema.ex
+++ b/priv/templates/phx.gen.embedded/embedded_schema.ex
@@ -4,8 +4,8 @@ defmodule <%= inspect schema.module %> do
   alias <%= inspect schema.module %>
 
   embedded_schema do
-<%= for {k, v} <- schema.types do %>    field <%= inspect k %>, <%= inspect v %><%= schema.defaults[k] %>
-<% end %>  end
+<%= Mix.Phoenix.Schema.format_fields_for_schema(schema) %>
+  end
 
   @doc false
   def changeset(%<%= inspect schema.alias %>{} = <%= schema.singular %>, attrs) do
diff --git a/priv/templates/phx.gen.schema/schema.ex b/priv/templates/phx.gen.schema/schema.ex
index 63a19d420..fc1d4788e 100644
--- a/priv/templates/phx.gen.schema/schema.ex
+++ b/priv/templates/phx.gen.schema/schema.ex
@@ -6,8 +6,8 @@ defmodule <%= inspect schema.module %> do
   @primary_key {:id, :binary_id, autogenerate: true}
   @foreign_key_type :binary_id<% end %>
   schema <%= inspect schema.table %> do
-<%= for {k, v} <- schema.types do %>    field <%= inspect k %>, <%= Mix.Phoenix.Schema.type_and_opts_for_schema(v) %><%= schema.defaults[k] %><%= Mix.Phoenix.Schema.maybe_redact_field(k in schema.redacts) %>
-<% end %><%= for {_, k, _, _} <- schema.assocs do %>    field <%= inspect k %>, <%= if schema.binary_id do %>:binary_id<% else %>:id<% end %>
+<%= Mix.Phoenix.Schema.format_fields_for_schema(schema) %>
+<%= for {_, k, _, _} <- schema.assocs do %>    field <%= inspect k %>, <%= if schema.binary_id do %>:binary_id<% else %>:id<% end %>
 <% end %>
     timestamps()
   end


Test patch:
diff --git a/test/mix/tasks/phx.gen.embedded_test.exs b/test/mix/tasks/phx.gen.embedded_test.exs
index 088e572af..e0526f8d7 100644
--- a/test/mix/tasks/phx.gen.embedded_test.exs
+++ b/test/mix/tasks/phx.gen.embedded_test.exs
@@ -1,4 +1,4 @@
-Code.require_file "../../../installer/test/mix_helper.exs", __DIR__
+Code.require_file("../../../installer/test/mix_helper.exs", __DIR__)
 
 defmodule Mix.Tasks.Phx.Gen.EmbeddedTest do
   use ExUnit.Case
@@ -12,57 +12,83 @@ defmodule Mix.Tasks.Phx.Gen.EmbeddedTest do
   end
 
   test "build" do
-    in_tmp_project "embedded build", fn ->
+    in_tmp_project("embedded build", fn ->
       schema = Gen.Embedded.build(~w(Blog.Post title:string))
 
       assert %Schema{
-        alias: Post,
-        module: Phoenix.Blog.Post,
-        repo: Phoenix.Repo,
-        migration?: false,
-        migration_defaults: %{title: ""},
-        plural: nil,
-        singular: "post",
-        human_plural: "Nil",
-        human_singular: "Post",
-        attrs: [title: :string],
-        types: %{title: :string},
-        embedded?: true,
-        defaults: %{title: ""},
-      } = schema
+               alias: Post,
+               module: Phoenix.Blog.Post,
+               repo: Phoenix.Repo,
+               migration?: false,
+               migration_defaults: %{title: ""},
+               plural: nil,
+               singular: "post",
+               human_plural: "Nil",
+               human_singular: "Post",
+               attrs: [title: :string],
+               types: %{title: :string},
+               embedded?: true,
+               defaults: %{title: ""}
+             } = schema
+
       assert String.ends_with?(schema.file, "lib/phoenix/blog/post.ex")
-    end
+    end)
   end
 
   test "generates embedded schema", config do
-    in_tmp_project config.test, fn ->
+    in_tmp_project(config.test, fn ->
       Gen.Embedded.run(~w(Blog.Post title:string))
-      assert_file "lib/phoenix/blog/post.ex", fn file ->
+
+      assert_file("lib/phoenix/blog/post.ex", fn file ->
         assert file =~ "embedded_schema do"
-      end
-    end
+      end)
+    end)
   end
 
   test "generates nested embedded schema", config do
-    in_tmp_project config.test, fn ->
+    in_tmp_project(config.test, fn ->
       Gen.Embedded.run(~w(Blog.Admin.User name:string))
 
-      assert_file "lib/phoenix/blog/admin/user.ex", fn file ->
+      assert_file("lib/phoenix/blog/admin/user.ex", fn file ->
         assert file =~ "defmodule Phoenix.Blog.Admin.User do"
         assert file =~ "embedded_schema do"
-      end
-    end
+      end)
+    end)
   end
 
   test "generates embedded schema with proper datetime types", config do
-    in_tmp_project config.test, fn ->
-      Gen.Embedded.run(~w(Blog.Comment title:string drafted_at:datetime published_at:naive_datetime edited_at:utc_datetime))
+    in_tmp_project(config.test, fn ->
+      Gen.Embedded.run(
+        ~w(Blog.Comment title:string drafted_at:datetime published_at:naive_datetime edited_at:utc_datetime)
+      )
 
-      assert_file "lib/phoenix/blog/comment.ex", fn file ->
+      assert_file("lib/phoenix/blog/comment.ex", fn file ->
         assert file =~ "field :drafted_at, :naive_datetime"
         assert file =~ "field :published_at, :naive_datetime"
         assert file =~ "field :edited_at, :utc_datetime"
-      end
-    end
+      end)
+    end)
+  end
+
+  test "generates embedded schema with enum", config do
+    in_tmp_project(config.test, fn ->
+      Gen.Embedded.run(
+        ~w(Blog.Comment comments title:string status:enum:unpublished:published:deleted)
+      )
+
+      assert_file("lib/phoenix/blog/comment.ex", fn file ->
+        assert file =~ "field :status, Ecto.Enum, values: [:unpublished, :published, :deleted]"
+      end)
+    end)
+  end
+
+  test "generates embedded schema with redact option", config do
+    in_tmp_project(config.test, fn ->
+      Gen.Embedded.run(~w(Blog.Comment comments title:string secret:redact))
+
+      assert_file("lib/phoenix/blog/comment.ex", fn file ->
+        assert file =~ "field :secret, :string, redact: true"
+      end)
+    end)
   end
 end