A new socket behaviour has been introduced to handle socket authentication in a single place, wire up default channel assigns, and disconnect a user's multiplex connection as needed.
First things first, create a UserSocket
module in web/channels/user_socket.ex
and move all your channel routes from web/route.ex
to the user socket: (replace MyApp with your application module)
0.14.x - web/router.ex:
defmodule MyApp.Router do
...
socket "/ws", MyApp do
channel "rooms:*", RoomChannel
end
end
0.15.0 - web/channels/user_socket.ex:
defmodule MyApp.UserSocket do
use Phoenix.Socket
## Channels
channel "rooms:*", MyApp.RoomChannel
## Transports
transport :websocket, Phoenix.Transports.WebSocket
transport :longpoll, Phoenix.Transports.LongPoll
# Socket params are passed from the client and can
# be used to verify and authenticate a user. After
# verification, you can put default assigns into
# the socket that will be set for all channels, ie
#
# {:ok, assign(socket, :user_id, verified_user_id)}
#
# To deny connection, return `:error`.
def connect(_params, socket) do
{:ok, socket}
end
# Socket id's are topics that allow you to identify all sockets for a given user:
#
# def id(socket), do: "users_socket:#{socket.assigns.user_id}"
#
# Would allow you to broadcast a "disconnect" event and terminate
# all active sockets and channels for a given user:
#
# MyApp.Endpoint.broadcast("users_socket:" <> user.id, "disconnect", %{})
#
# Returning `nil` makes this socket anonymous.
def id(_socket), do: nil
end
Leaving the default implementations of connect/2
and id/1
will give you the same behavour you had with 0.14.x.
Next, remove the socket
mount from your Router and add it to your lib/my_app/endpoint.ex
and add a mount for phoenix live reload if using :phoenix_live_reload
:
defmodule MyApp.Endpoint do
use Phoenix.Endpoint, otp_app: :my_app
socket "/ws", MyApp.UserSocket
plug Plug.Static, ...
# Code reloading can be explicitly enabled under the
# :code_reloader configuration of your endpoint.
if code_reloading? do
socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
plug Phoenix.LiveReloader
plug Phoenix.CodeReloader
end
...
end
If using handle_out/3
callbacks in your channels, you now must explicit list which events you want your channels to intercept and pass through handle_out. This change brings large performance improvements by caching encodings across all subscribers if the event is not intercepted by the channel:
0.14.x:
defmodule MyApp.RoomChannel do
use MyApp.Web, :channel
...
def handle_out("new_msg", payload, socket) do
push socket, "new_msg", %{role: socket.assigns.role, body: payload["body"]}
{:noreply, socket}
end
end
0.15.0:
defmodule MyApp.RoomChannel do
use MyApp.Web, :channel
intercept ["new_msg"]
...
def handle_out("new_msg", payload, socket) do
push socket, "new_msg", %{role: socket.assigns.role, body: payload["body"]}
{:noreply, socket}
end
end
Next update your :phoenix
, :phoenix_html
, :phoenix_ecto
, and :phoenix_live_reload
deps in mix.exs
:
def deps do
[...,
{:phoenix, "~> 0.15"},
{:phoenix_ecto, "~> 0.8"},
{:phoenix_html, "~> 1.4"},
{:phoenix_live_reload, "~> 0.5", only: :dev},
...]
end
Next, run $ mix deps.update
We are updating two versions fo Ecto from version 0.12 to 0.14/0.15-dev most of the changes you need to make will be reflected in this section taken from the Ecto Changelog. If you have further issues or compiler errors please check the Ecto Changelog for further details.
Below is taken from the change for v0.13 backwards incompatible changes.
Ecto.Repo.update!/2
no longer invokes callbacks if there were no changes, avoiding writing to the database at all (use:force
to force callback execution)Ecto.Repo.transaction/2
is now flattened. This means that multiple transaction calls will no longer use savepoints, instead it will be considered as a single transaction, where a failure in any transaction block will trigger the outmost transaction to rollback, even if failures are rescued. This should only affect users that were explicitly relying on the savepoints.:date
,:time
and:datetime
were removed in favor ofEcto.Date
,Ecto.Time
andEcto.DateTime
Ecto.Changeset.errors
now return{"must be less than %{count}", count: 3}
instead of{"must be less than %{count}", 3}