We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Post 90
LiveView 05 - Chapter 3 Generators
Published on: 2025-12-04
Tags:
elixir, Blog, Side Project, Testing, LiveView, Ecto, Html/CSS, Phoenix
Chapter 3 Generators: Contexts and Schemas
For the next phase of the project we will be building a project catalog for our project using as many generators as possible. The Generators are great a building any CRUD feature that you want. Plus there is built in features to go beyond that.
Here is the plan for the first feature:
Run the Generator
Focus on the Backend
Schema
API Layer
Focus on the Frontend
Get to Know the Phoenix Live Generator
mix phx.gen.live is a script that generates code supporting full CRUD. It also will build routes that can take care of the frontend for templates.
The biggest part of a generator is the use of macros, code that writes code. The next is the generic code that is created to take care of the basic part of the framework. However if this basic framework isn't done to standard and supports additions it can only be used for a specific task.
Run the Phoenix Live Generator
Here we will build a product manager for our site. This will be a resource called Product the generator will create the CRUD for that resource. The frontend will reside in the lib/pento_web while the backend will reside in lib/pento. The way in which we handle all the interactions will be the context (API).
Once we are done we will have a schema for a Product and a Catalog context, along with live views for managing a product.
The HTTP request through the route /products will be handled by the live view (Context) and then the schema will be called by that top layer to deal with the database.
With this out of the way let's fire up the generator!!
Learn How To Use the Generator
The syntax for a generator will need a context and a schema. We will also need to tell Phoenix which fields to support for the resource. Let's run the generator without options to see some helpful docs.
$ mix phx.gen.live
...compiling...
** (Mix) Invalid arguments
mix phx.gen.html, phx.gen.json, phx.gen.live, and phx.gen.context
expect a context module name, followed by singular and plural names
of the generated resource, ending with any number of attributes.
For example:
mix phx.gen.html Accounts User users name:string
mix phx.gen.json Accounts User users name:string
mix phx.gen.live Accounts User users name:string
mix phx.gen.context Accounts User users name:string
The context serves as the API boundary for the given resource.
Multiple resources may belong to a context and a resource may be
split over distinct contexts (such as Accounts.User and Payments.User).
----------
Let's break down that example mix phx.gen.live Accounts User users name:string
Accounts is the context
User is the schema
The pairs that follow are the fields that will be in our database
Generate a Resource
Let's run the actual syntax that we want for our new context
mix phx.gen.live Catalog Product products name:string \
description:string unit_price:float sku:integer:unique
* creating lib/pento_web/live/product_live/show.ex
* creating lib/pento_web/live/product_live/index.ex
* creating lib/pento_web/live/product_live/form.ex
* creating test/pento_web/live/product_live_test.exs
* creating lib/pento/catalog/product.ex
* creating priv/repo/migrations/20250724132712_create_products.exs
* creating lib/pento/catalog.ex
* injecting lib/pento/catalog.ex
* creating test/pento/catalog_test.exs
* injecting test/pento/catalog_test.exs
* creating test/support/fixtures/catalog_fixtures.ex
* injecting test/support/fixtures/catalog_fixtures.ex
Add the live routes to your browser scope in lib/pento_web/router.ex:
live "/products", ProductLive.Index, :index
live "/products/new", ProductLive.Form, :new
live "/products/:id", ProductLive.Show, :show
live "/products/:id/edit", ProductLive.Form, :edit
Ensure the routes are defined in a block that sets the :current_scope assign.
-----
Okays now that we have the files it tells us to be sure that we add in the new routes to a block we will add them into the scope that contains the :require_authenticated_user and the live session block pento/lib/pento_web/router.ex
scope "/", PentoWeb do
pipe_through([:browser, :require_authenticated_user])
live_session :require_authenticated_user,
root_layout: {PentoWeb.Layouts, :root},
on_mount: [{PentoWeb.UserAuth, :require_authenticated}] do
live("/users/settings", UserLive.Settings, :edit)
live("/users/settings/confirm-email/:token", UserLive.Settings, :confirm_email)
live("/products", ProductLive.Index, :index)
live("/products/new", ProductLive.Form, :new)
live("/products/:id", ProductLive.Show, :show)
live("/products/:id/edit", ProductLive.Form, :edit)
end
post("/users/update-password", UserSessionController, :update_password)
end
live is a macro that will start a new live session and pass in 3 arguments,
The route ("/products")
The module (Product.Index)
The live action (:new)
Verify the Generated Code
Let's test the code to be sure that the initial setup works as needed. Let's run the tests.
[pento] ➔ mix test
..................................................................
..................................................................
...............
Finished in 0.3 seconds (0.1s async, 0.1s sync)
122 tests, 0 failures
Randomized with seed 829064
Now let's look at how the test deal with automatic authentication.
setup :register_and_log_in_user
defp create_product(%{scope: scope}) do
product = product_fixture(scope)
%{product: product}
end
setup :register_and_log_in_user will create a user and log them in while making sure that we deal with the scope.
Understanding Scope-Aware Fixtures
With this understanding about the scope and how it functions within any call. We will see that fixtures will take the scope as a parameter and use that to do anything within the context of the context of the new resource.
def product_fixture(scope, attrs \\ %{}) do
attrs =
Enum.into(attrs, %{
description: "some description",
name: "some name",
sku: unique_product_sku(),
unit_price: 120.5
})
{:ok, product} = Pento.Catalog.create_product(scope, attrs)
product
end
The Job of Scopes in Testing
Data Isolation
Security Verification
Realistic Testing
Simplified Setup