Channels
To invoke the socket generator:
Specifying the socket handler in endpoint
socket "/socket", HelloWeb.UserSocket,
websocket: true,
longpoll: false
Socket connection in the javascript client
let socket = new Socket("/socket", {params: {token: window.userToken}})
Channel specification for the user socket in the server:
channel "room:*", HelloWeb.RoomChannel
Room channel in lib/hello_web/channels/room_channel.ex
:
defmodule HelloWeb.RoomChannel do
use Phoenix.Channel
def join("room:lobby", _message, socket) do
{:ok, socket}
end
def join("room:" <> _private_room_id, _params, _socket) do
{:error, %{reason: "unauthorized"}}
end
end
Presence
To use Presence we should use the presence generator:
And add the new Presence created to the app supervision tree:
children = [
...
HelloWeb.Presence,
]
And after that create the channel we want to communicate presence over:
defmodule HelloWeb.RoomChannel do
use Phoenix.Channel
alias HelloWeb.Presence
def join("room:lobby", %{"name" => name}, socket) do
send(self(), :after_join)
{:ok, assign(socket, :name, name)}
end
def handle_info(:after_join, socket) do
{:ok, _} =
Presence.track(socket, socket.assigns.name, %{
online_at: inspect(System.system_time(:second))
})
push(socket, "presence_state", Presence.list(socket))
{:noreply, socket}
end
end
And finally add the functionality to the client app, in this case list the users list, rendering it in a div with id=connections
:
function renderOnlineUsers(presence) {
let response = ""
presence.list((id, {metas: [first, ...rest]}) => {
let count = rest.length + 1
response += `<br>${id} (count: ${count})</br>`
})
document.querySelector("div[id=connections]").innerHTML = response
}
Ecto
To create a User schema with four fields we use the mix phx.gen.schema
:
mix phx.gen.schema User users name:string email:string bio:string number_of_pets:integer
After this we should migrate to create the tables in the database:
Example of a migration with timestamps:
defmodule Hello.Repo.Migrations.CreateUsers do
use Ecto.Migration
def change do
create table(:users) do
add :name, :string
add :email, :string
add :bio, :string
add :number_of_pets, :integer
timestamps()
end
end
end
Example of a changeset with validations:
def changeset(%User{} = user, attrs) do
user
|> cast(attrs, [:name, :email, :bio, :number_of_pets])
|> validate_length(:bio, min: 2)
|> validate_length(:bio, max: 140)
|> validate_required([:name, :email, :bio, :number_of_pets])
end
Inserting an user to the data base with Repo: