Elixir Phoenix PubSub Tutorial: Difference between revisions

From ElixirBlocks
Jump to: navigation, search
No edit summary
Line 196: Line 196:
===A Useful Mental Modal===
===A Useful Mental Modal===


Mental Modals are useful not because they are 100 percent accurate but because they are useful. The mental modal I use regarding how these functions interact is simple.
Mental Models are helpful not because they are 100 percent accurate but because they are tangibly useful. The mental modal I use regarding how these functions interact is simple and is as follows:


Broadcast transmits information to subscribe and if the first two arguments of broadcast  match those in subscribe, then subscribe enables the handle_info of its containing module to receive the payload from broadcast. Handle_info will only recognize data that "matches" the shape of its first parameter.


If the first two arguments of broadcast and subscribe match, handle_info is enabled with the ability to receive payload data from broadcast.


THis may be confusing because you might assume handle_info would have to be given the same "topic" at the other two functions. This is not the case. As long as handle_info is in the same Live View module as the subscribe that matches the broadcast, it automatically recognizes the incoming payload data.


=== Explanation ===
=== Explanation ===

Revision as of 04:49, 27 August 2023

This page is in progress


Prerequisites

You should know how to launch a 1 page Live View app that lets the user submit data via a form. The form data should print to the page.




This tutorial explains the basics of building a Phoenix PubSub chat app.

The goal of this writing is to explain how to write code used to build PubSub applications in Phoenix. I tried to write examples that keep code writing to a minimum. I believe minimalist examples are the best approach toward comprehension.

The tutorial is divided into three parts, each part building on the completion of the previous one.

Project Description

  • Part 1: We create a two route live view app with each route assigned its own page. The two routes are /send and /receive.

The page at /send contains an html form and form submission code. When data is submitted, the /receive page receives the data, and renders it to its page. The code we write for this exercise uses pubsub functions to connect the two LiveView pages.

When complete, you will have two browser tabs open, one opened to /send and one opened to /receive. The /send route sends data to /receive and you view the update in real time.

  • Part 2: We convert the previous app into a single LiveView page that performs both actions on a single route. The end result is the creation of a single page chat application containing real time updates that you view across browser tabs.
  • Part 3: We write code to update your single page app to store chat data in a database.



Part 1

Setup

To begin we will start with an new Phoenix instance. In your terminal create a new phoenix app by typing:

mix phx.new app

When the console prompts you to Fetch and install dependencies, choose yes.

When you see the following instructions configure your database, run mix ecto.create.



We are almost there! The following steps are missing:

    $ cd app

Then configure your database in config/dev.exs and run:

    $ mix ecto.create

Start your Phoenix app with:

    $ mix phx.server

You can also run your app inside IEx (Interactive Elixir) as:

    $ iex -S mix phx.server



If you are new to Elixir and are having trouble with database setup, please fix those issues before proceeding with this tutorial.

When the app is created, open your web browser to localhost:4000. The app will launch. If it doesn't, fix the errors before moving forward.


Create Routes

Go to the router and update it as shown.

directory: app/app_web/router.ex

  scope "/", AppWeb do
    pipe_through :browser
    live "/send", SendLive, :home
    live "/receive", ReceiveLive, :home
    get "/", PageController, :home
  end

Create the LiveView Pages

Create a new folder named live in this directory: App/lib/app_web. The end result will look like this: App/lib/app_web/live.

In the live directory, create two files and name them send_live.ex and receive_live.ex.


Edit Send Live.ex

Open the file send_live.ex in your text editor. Paste the following code into it.

defmodule AppWeb.SendLive do
  use AppWeb, :live_view
  
  def mount(_params, _session, socket) do
    {:ok, socket}
  end
  
  def handle_event("send", %{"text" => text}, socket) do
    IO.inspect text

    Phoenix.PubSub.broadcast(App.PubSub, "message", {:text_stuff, text}) 

    {:noreply, socket}
  end
  
  defp topic do #Topic
    "message"
  end

  def render(assigns)do   
   ~H"""
    <div>
      <h1>Send Message</h1>
      <form phx-submit="send">
        <input type="text" name="text" />
        <button type="submit">Send</button>
      </form>
    </div>

    """
  end
end


Open receive_live.ex and copy the following code to it.

defmodule AppWeb.ReceiveLive do
  use AppWeb, :live_view
  
  def mount(_params, _session, socket) do

    if connected?(socket) do
      Phoenix.PubSub.subscribe(App.PubSub, topic)    
    end

    {:ok, assign(socket, message_item: "")}
  end
  
  def handle_info({:text_stuff, text}, socket) do 
    {:noreply, assign(socket, message_item: text)}
  end

  defp topic do  # Topic
    "message"
  end

  def render(assigns)do   
   ~H"""
     <div>
    <h1>ChatLive</h1>
    <%= @message_item %>
    </div>

    """
  end
  
end



Before learning how this code works, first launch the server and open up two browser tabs. Set one to /send and the other to /receive

Submit data from /send and view the result on /receive

Play with the code and explore it. Ensure that it works.

Description

Before explaining the code, I would like to summarize the important parts applicable to PubSub applications. Direct your attention to the three functions listed below. You can look at these functions as the main characters in a PubPub program.

  • Phoenix.PubSub.broadcast(App.PubSub, topic, {:text_stuff, text})
  • Phoenix.PubSub.subscribe(App.PubSub, topic)
  • handle_info({:text_stuff, text}, socket)

For brevity I refer to these as broadcast,subscribe and handle_info.

All PubSub applications are composed of these three functions.

A Useful Mental Modal

Mental Models are helpful not because they are 100 percent accurate but because they are tangibly useful. The mental modal I use regarding how these functions interact is simple and is as follows:


If the first two arguments of broadcast and subscribe match, handle_info is enabled with the ability to receive payload data from broadcast.


THis may be confusing because you might assume handle_info would have to be given the same "topic" at the other two functions. This is not the case. As long as handle_info is in the same Live View module as the subscribe that matches the broadcast, it automatically recognizes the incoming payload data.

Explanation

1. In SendLive the code Phoenix.PubSub.broadcast is used to broadcast a message. This method takes three arguments.

  • The pubsub type
  • The topic
  • The payload (the data you want to send to all listeners)

The pubsub type is always going to be the name of your app dot app. For our purposes you can treat this as boiler plate code. The topic is a string that represents a connection