Skip to content

Commit

Permalink
Merge branch 'phoenixframework:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
RobinBoers committed Dec 2, 2024
2 parents 1515e79 + 195d890 commit cbc33c3
Show file tree
Hide file tree
Showing 87 changed files with 621 additions and 403 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ See the official site at <https://www.phoenixframework.org/>.

Install the latest version of Phoenix by following the instructions at <https://hexdocs.pm/phoenix/installation.html#phoenix>.

Phoenix requires Elixir v1.11+ & Erlang v22.1+.

## Documentation

API documentation is available at <https://hexdocs.pm/phoenix>.
Expand Down Expand Up @@ -44,29 +42,31 @@ defp deps do

To create projects outside of the `installer/` directory, add the latest archive to your machine by following the instructions in [installer/README.md](https://github.com/phoenixframework/phoenix/blob/main/installer/README.md)

To build the documentation from source:
### Building from source

To build the documentation:

```bash
npm install --prefix assets
MIX_ENV=docs mix docs
```

To build Phoenix from source:
To build Phoenix:

```bash
mix deps.get
mix compile
```

To build the Phoenix installer from source:
To build the Phoenix installer:

```bash
mix deps.get
mix compile
mix archive.build
```

### Building phoenix.js
To build Phoenix.js:

```bash
cd assets
Expand Down
2 changes: 1 addition & 1 deletion guides/authentication/api_authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ To make sure our new functions work, let's write tests. Open up `test/my_app/acc

If you run the tests, they will actually fail. Something similar to this:

```elixir
```console
1) test create_user_api_token/1 and fetch_user_by_api_token/1 creates and verify token (Demo.AccountsTest)
test/demo/accounts_test.exs:21
** (FunctionClauseError) no function clause matching in Demo.Accounts.UserToken.days_for_context/1
Expand Down
4 changes: 2 additions & 2 deletions guides/components.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ We declared the attributes we accept via the `attr/3` macro provided by `Phoenix

Next we need to update `show.html.heex`:

```elixir
```heex
<section>
<.greet messenger={@messenger} />
</section>
Expand Down Expand Up @@ -92,7 +92,7 @@ Next, let's fully understand the expressive power behind the HEEx template langu
Function components and templates files are powered by [the HEEx template language](https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html#sigil_H/2), which stands for "HTML+EEx". EEx is an Elixir library that uses `<%= expression %>` to execute Elixir expressions and interpolate their results into the template. This is frequently used to display assigns we have set by way of the `@` shortcut. In your controller, if you invoke:

```elixir
render(conn, :show, username: "joe")
render(conn, :show, username: "joe")
```

Then you can access said username in the templates as `<%= @username %>`. In addition to displaying assigns and functions, we can use pretty much any Elixir expression. For example, in order to have conditionals:
Expand Down
3 changes: 1 addition & 2 deletions guides/contexts.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,6 @@ $ mix ecto.gen.migration create_product_categories
Next, let's open up the new migration file and add the following code to the `change` function:

```elixir

defmodule Hello.Repo.Migrations.CreateProductCategories do
use Ecto.Migration

Expand Down Expand Up @@ -521,7 +520,7 @@ With our `category_opts` function in place, we can open up `lib/hello_web/contro

We added a `category_select` above our save button. Now let's try it out. Next, let's show the product's categories in the product show template. Add the following code to the list in `lib/hello_web/controllers/product_html/show.html.heex`:

```heex
```diff
<.list>
...
+ <:item title="Categories">
Expand Down
2 changes: 1 addition & 1 deletion guides/deployment/fly.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ $ fly deploy

Note: On Apple Silicon (M1) computers, docker runs cross-platform builds using qemu which might not always work. If you get a segmentation fault error like the following:

```
```console
=> [build 7/17] RUN mix deps.get --only
=> => # qemu: uncaught target signal 11 (Segmentation fault) - core dumped
```
Expand Down
4 changes: 2 additions & 2 deletions guides/deployment/gigalixir.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ For a free tier database, update your `Repo` config with:
```elixir
ssl: true,
ssl_opts: [
  verify: :verify_none,
  cacerts: :public_key.cacerts_get()
verify: :verify_none,
cacerts: :public_key.cacerts_get()
]
```

Expand Down
4 changes: 2 additions & 2 deletions guides/ecto.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ iex> changeset.errors
Now, let's make `number_of_pets` optional. In order to do this, we simply remove it from the list in the `changeset/2` function, in `Hello.User`.

```elixir
|> validate_required([:name, :email, :bio])
|> validate_required([:name, :email, :bio])
```

Now casting the changeset should tell us that only `name`, `email`, and `bio` can't be blank. We can test that by running `recompile()` inside IEx and then rebuilding our changeset.
Expand Down Expand Up @@ -529,7 +529,7 @@ Let's open up our `mix.exs` file and do that now.
defmodule HelloPhoenix.MixProject do
use Mix.Project

. . .
...
# Specifies your project dependencies.
#
# Type `mix help deps` for examples and options.
Expand Down
2 changes: 1 addition & 1 deletion guides/howto/custom_error_pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ config :hello, HelloWeb.Endpoint,
http: [port: 4000],
debug_errors: false,
code_reloader: true,
. . .
...
```

After modifying our config file, we need to restart our server in order for this change to take effect. After restarting the server, let's go to [http://localhost:4000/such/a/wrong/path](http://localhost:4000/such/a/wrong/path) for a running local application and see what we get.
Expand Down
8 changes: 4 additions & 4 deletions guides/howto/file_uploads.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ Here is the form from `lib/hello_web/controllers/product_html/product_form.html.

```heex
<.simple_form :let={f} for={@changeset} action={@action} multipart>
. . .
...
```

### Add a file input

Once you have a multipart form, you need a `file` input. Here's how you would do that, also in `product_form.html.heex`:

```heex
. . .
...
<.input field={f[:photo]} type="file" label="Photo" />
<:actions>
Expand Down Expand Up @@ -71,10 +71,10 @@ Since you generated an HTML resource, you can now start your server with `mix ph
Before you begin, add `IO.inspect product_params` to the top of your `ProductController.create/2` action in `lib/hello_web/controllers/product_controller.ex`. This will show the `product_params` in your development log so you can get a better sense of what's happening.

```elixir
. . .
...
def create(conn, %{"product" => product_params}) do
IO.inspect product_params
. . .
...
```

When you do that, this is what your `product_params` will output in the log:
Expand Down
8 changes: 0 additions & 8 deletions guides/introduction/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,6 @@ Please take a look at this list and make sure to install anything necessary for

Phoenix is written in Elixir, and our application code will also be written in Elixir. We won't get far in a Phoenix app without it! The Elixir site maintains a great [Installation Page](https://elixir-lang.org/install.html) to help.

If we have just installed Elixir for the first time, we will need to install the Hex package manager as well. Hex is necessary to get a Phoenix app running (by installing dependencies) and to install any extra dependencies we might need along the way.

Here's the command to install Hex (If you have Hex already installed, it will upgrade Hex to the latest version):

```console
$ mix local.hex
```

## Erlang 24 or later

Elixir code compiles to Erlang byte code to run on the Erlang virtual machine. Without Erlang, Elixir code has no virtual machine to run on, so we need to install Erlang as well.
Expand Down
22 changes: 11 additions & 11 deletions guides/json_and_apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ The API scope uses the `:api` pipeline, which will run specific steps such as en
Then we need to update our repository by running migrations:

```console
mix ecto.migrate
$ mix ecto.migrate
```

### Trying out the JSON API
Expand All @@ -62,13 +62,13 @@ Before we go ahead and change those files, let's take a look at how our API beha
First, we need to start the server:

```console
mix phx.server
$ mix phx.server
```

Next, let's make a smoke test to check our API is working with:

```console
curl -i http://localhost:4000/api/urls
$ curl -i http://localhost:4000/api/urls
```

If everything went as planned we should get a `200` response:
Expand All @@ -88,31 +88,31 @@ x-request-id: Fuyg-wMl4S-hAfsAAAUk
We didn't get any data because we haven't populated the database with any yet. So let's add some links:

```console
curl -iX POST http://localhost:4000/api/urls \
$ curl -iX POST http://localhost:4000/api/urls \
-H 'Content-Type: application/json' \
-d '{"url": {"link":"https://phoenixframework.org", "title":"Phoenix Framework"}}'

curl -iX POST http://localhost:4000/api/urls \
$ curl -iX POST http://localhost:4000/api/urls \
-H 'Content-Type: application/json' \
-d '{"url": {"link":"https://elixir-lang.org", "title":"Elixir"}}'
```

Now we can retrieve all links:

```console
curl -i http://localhost:4000/api/urls
$ curl -i http://localhost:4000/api/urls
```

Or we can just retrieve a link by its `id`:

```console
curl -i http://localhost:4000/api/urls/1
$ curl -i http://localhost:4000/api/urls/1
```

Next, we can update a link with:

```console
curl -iX PUT http://localhost:4000/api/urls/2 \
$ curl -iX PUT http://localhost:4000/api/urls/2 \
-H 'Content-Type: application/json' \
-d '{"url": {"title":"Elixir Programming Language"}}'
```
Expand All @@ -122,7 +122,7 @@ The response should be a `200` with the updated link in the body.
Finally, we need to try out the removal of a link:

```console
curl -iX DELETE http://localhost:4000/api/urls/2 \
$ curl -iX DELETE http://localhost:4000/api/urls/2 \
-H 'Content-Type: application/json'
```

Expand Down Expand Up @@ -291,7 +291,7 @@ As we can see, it will convert the errors into a data structure, which will be r
As you can see, the changeset requires both link and title to be given. This means we can try posting a url with no link and title and see how our API responds:

```console
curl -iX POST http://localhost:4000/api/urls \
$ curl -iX POST http://localhost:4000/api/urls \
-H 'Content-Type: application/json' \
-d '{"url": {}}'

Expand All @@ -310,7 +310,7 @@ for the REST API.
From your terminal run:

```console
mix help phx.new
$ mix help phx.new
```

The output should contain the following:
Expand Down
16 changes: 8 additions & 8 deletions guides/mix_tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -583,29 +583,29 @@ Don't forget to add your new repo to your supervision tree
Notice that this task has updated `config/config.exs`. If we take a look, we'll see this extra configuration block for our new repo.

```elixir
. . .
...
config :hello, OurCustom.Repo,
username: "user",
password: "pass",
hostname: "localhost",
database: "hello_repo",
. . .
...
```

Of course, we'll need to change the login credentials to match what our database expects. We'll also need to change the config for other environments.

We certainly should follow the instructions and add our new repo to our supervision tree. In our `Hello` application, we would open up `lib/hello/application.ex`, and add our repo as a worker to the `children` list.

```elixir
. . .
...
children = [
Hello.Repo,
# Our custom repo
OurCustom.Repo,
# Start the endpoint when the application starts
HelloWeb.Endpoint,
]
. . .
...
```

### `mix ecto.gen.migration`
Expand Down Expand Up @@ -638,15 +638,15 @@ Notice that there is a single function `change/0` which will handle both forward
What we want to do is create a `comments` table with a `body` column, a `word_count` column, and timestamp columns for `inserted_at` and `updated_at`.

```elixir
. . .
...
def change do
create table(:comments) do
add :body, :string
add :word_count, :integer
timestamps()
end
end
. . .
...
```

Again, we can run this task with the `-r` flag and another repo if we need to.
Expand Down Expand Up @@ -707,13 +707,13 @@ $ mix ecto.migrate -n 2
The `--step` option will behave the same way.

```console
mix ecto.migrate --step 2
$ mix ecto.migrate --step 2
```

The `--to` option will run all migrations up to and including given version.

```console
mix ecto.migrate --to 20150317170448
$ mix ecto.migrate --to 20150317170448
```

### `mix ecto.rollback`
Expand Down
2 changes: 1 addition & 1 deletion guides/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ end

When we run `mix phx.routes` now, in addition to the routes we saw for `users` above, we get the following set of routes:

```elixir
```console
...
GET /users/:user_id/posts HelloWeb.PostController :index
GET /users/:user_id/posts/:id/edit HelloWeb.PostController :edit
Expand Down
39 changes: 37 additions & 2 deletions installer/templates/phx_assets/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import "phoenix_html"
<%= @live_comment %>import {LiveSocket} from "phoenix_live_view"
<%= @live_comment %>import topbar from "../vendor/topbar"

<%= @live_comment %>let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
<%= @live_comment %>let liveSocket = new LiveSocket("/live", Socket, {
<%= @live_comment %>const csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
<%= @live_comment %>const liveSocket = new LiveSocket("/live", Socket, {
<%= @live_comment %> longPollFallbackMs: 2500,
<%= @live_comment %> params: {_csrf_token: csrfToken}
<%= @live_comment %>})
Expand All @@ -41,4 +41,39 @@ import "phoenix_html"
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
// >> liveSocket.disableLatencySim()
<%= @live_comment %>window.liveSocket = liveSocket

// The lines below enable quality of life phoenix_live_reload
// development features:
//
// 1. stream server logs to the browser console
// 2. click on elements to jump to their definitions in your code editor
//
<%= @live_comment %>if (process.env.NODE_ENV === "development") {
<%= @live_comment %> window.addEventListener("phx:live_reload:attached", ({detail: reloader}) => {
<%= @live_comment %> // Enable server log streaming to client.
<%= @live_comment %> // Disable with reloader.disableServerLogs()
<%= @live_comment %> reloader.enableServerLogs()
<%= @live_comment %>
<%= @live_comment %> // Open configured PLUG_EDITOR at file:line of the clicked element's HEEx component
<%= @live_comment %> //
<%= @live_comment %> // * click with "c" key pressed to open at caller location
<%= @live_comment %> // * click with "d" key pressed to open at function component definition location
<%= @live_comment %> let keyDown
<%= @live_comment %> window.addEventListener("keydown", e => keyDown = e.key)
<%= @live_comment %> window.addEventListener("keyup", e => keyDown = null)
<%= @live_comment %> window.addEventListener("click", e => {
<%= @live_comment %> if(keyDown === "c"){
<%= @live_comment %> e.preventDefault()
<%= @live_comment %> e.stopImmediatePropagation()
<%= @live_comment %> reloader.openEditorAtCaller(e.target)
<%= @live_comment %> } else if(keyDown === "d"){
<%= @live_comment %> e.preventDefault()
<%= @live_comment %> e.stopImmediatePropagation()
<%= @live_comment %> reloader.openEditorAtDef(e.target)
<%= @live_comment %> }
<%= @live_comment %> }, true)
<%= @live_comment %>
<%= @live_comment %> window.liveReloader = reloader
<%= @live_comment %> })
<%= @live_comment %>}
<% end %>
Loading

0 comments on commit cbc33c3

Please sign in to comment.