Programming Phoenix LiveView Book Club!

Hey, I just realized that I totally missed the point of your previous messages.
I was just cloning your repo and visiting /guess thats why I was under the impression that everything was fine.

About the live_patch error, I’m also no sure about that, but using the new link component seems to work just fine.

  def render(assigns) do
    ~H"""
    <h1>Your score: <%= @score %></h1>
    <h2>
      <%= @message %> It's <%= @time %>
    </h2>
    <h2>
      <%= for n <- 1..10 do %>
        <.link href="#" phx-click="guess" phx-value-number={n}>
          <%= n %>
        </.link>
      <% end %>
    </h2>
    <%= if @over do %>
      <.link patch={~p"/guess"}>Try again</.link>
    <% end %>
    """
  end

  def handle_params(_params, _uri, socket) do
    socket = assign(socket, score: 0,
    time: time(),
    message: "Make a guess:",
    secret_number: generate_a_random_number(),
    over: false)

    {:noreply, socket}
  end
1 Like

Looking into live_path will reveal the mystery. It being a macro doesn’t seem to be a straight forward code to investigate into.

@m4hi2 could you downgrade the LiveView version to 0.17/0.16 and see if it persists?

1 Like

In case you haven’t solved the issue yet:

If you are using a new version of LiveView, you are getting an error because the functions you are trying to use does not exist anymore, they have been deprecated. If we look at the LiveView docs we can see that live_patch was deprecated in version 0.18.0 (current version is 0.18.18). The functionality you should use instead is described in Live navigation :slight_smile:

3 Likes

Chapter 1

Not too much to say about this chapter. It’s a nice little introduction to LiveView and the philosophy behind it. The chapters give some insight into the building blocks of LiveView such as the Socket struct, Websockets and how diffs are used to minimize data sent over the network. And of course, the LiveView lifecycle and loop.

The chapter is also used to hype up the technology a bit with sentences such as “As a result of these Elixir language features, users would find a pleasant, productive programming experience in Phoenix LiveView.” and “As a result, in LiveView, programmers would find a beautiful programming model based on tested concepts, …”.

All in all, since I’ve used LiveView a bit before, it was not much that I hadn’t heard before.
I have one question though. In the very last part of the Your Turn section where you are encouraged to use the patch functionality in order to restart the guessing game, is there some benefit in using patch and handle_params instead of sending an event and using a handle_event function? Or is it just a way of getting the reader aware of the patch functionality in LiveView?

Finally, there is an error here. The reference link to the (deprecated) live_path is broken. This error has already been reported though :slight_smile:

Time to get started with the next chapter!

5 Likes

Chapter 2

Now, this was a chapter that introduced a lot of concepts. Code generators, Plug, the endpoint and router, policies, scopes, routes, authentication etc. This is probably a chapter one should read through 2 times in order for everything to sink in.

The absolute biggest takeaway, for me, in this chapter was the concept of CRC (Constructors, Reducers, Converters). Somehow I have managed to avoid this mental model until now, but it just makes so much sense when trying to understand how to think about plugs.
The idea of taking some sort of input (the request), parse it into a datatype (Conn struct), perform some functions on the data in a pipeline manner (plugs), and lastly convert it into an output (response) made it very clear to me what was going on. Something seemingly complex turned simple! :smiley:

Exercises

Mailer: I don’t have a mailing service, but after looking into it, it seems like you only need to add some Swoosh config and it “just works”. Please correct me if I’m wrong.

Username: I deleted the user I created going through the chapter so that I could enforce every user to have a username, hehe. Doing the migration, making the changes to User and adding the form input in the registration was not much code. But adding the “change username” functionality seemed to require quite a lot of code and steps, so I didn’t go that far.

Redirect: A one row change to the PageController.

Session id: A small change to the on_mount function.

Errata

On page 56 the authors show you how to add a root layout to your live_session:
root_layout: {PentoWeb.LayoutView, :root}
This will result in an error. What they meant was probably:
root_layout: {PentoWeb.Layouts, :root}

This error has already been reported :slight_smile:

Looking forward to Chapter 3 ^^

6 Likes

This book is amazing!

I wanted to read it for start to end first and then a second time while posting about the chapters (to not have the same debacle as last book club I participated in). But I just have to post this roaring, premature conclusion.

Concepts are exceptionally well explained (such as the CRC as mentioned in the post above) and then referred to when you ‘see them again’.

Currently at page 218 and those were 218 pages of joy. I mark the “this is significant stuff” sections and already have about 60 marks, only 4 of them are “maybe change this” nitpicks (the other 56 I will post about later)

Page 121: typo: comment → common
Page 121: better use the new :if directive
Page 173: “Elixir will always use Ecto to transact against the database”. Seems a bit bold as if they are married.
Page 198: LiveView now uses ‘stream’ in the generated code. Guess that is being updated before final.

4 out of 60 is a very impressive ratio.

Want a pleasant time? Go read this book :slight_smile:

6 Likes

Chapter 3

Fantastic chapter! It is basically a chapter about structuring Elixir software, and some very valuable concepts are introduced.

The most important takeaway for me from this chapter was the concept of the Context and the Core of a resource.

The Context

The context is the API to the resource, every interaction with the resource goes through the context module (in this case the Products module). Every unpure function goes here (functions that can perform I/O, might fail, etc.). The with function can often be put to good use in the context.

The Core

All pure functions go here. The schema, query builders, etc. Core functions are often suitable for piping.

Best quotes of the chapter:

  • “The Context API is with-land”
  • “The Core is pipe-land”

Now, in the code used so far, the context and the core is very easy to separate since it’s just the Products module and the Product module. I hope the book will keep referring to these concepts as the application grows.

Next up is the frontend in Chapter 4 :smiley:

7 Likes

Indeed. This chapter is gold, even for non-Phoenix projects. The pipe- & with-land is very easy to remember and the explanation for the Context module is the best I read so far.

4 Likes

Hello all,

I’m new to Elixir and Phoenix. I’m also early in my career as a developer. I got the book a few weeks ago and this book club inspired me to really start cracking into it!

Here’s what I’ve got for Chapter 1 (B0.9.0)

:drum: :drum: :drum: :drum: Chapter 1 Awards :drum: :drum: :drum: :drum:

  • :open_book: Most Rereadable Section :open_book:
    Build a Simple Live View (pp. 15-23)
    As a relatively new Phoenix/Elixir user, it was helpful for me to read this section several times. The subsection titled Understand the LiveView Loop was most valuable to me. It removed some of the magic and gave me a better understanding of the importance of event handlers. I’m sure that some of the other sections will become more valuable for me to reread as I continue to learn.

  • :rabbit2: Most Likely to Send You Down The Rabbit Hole :rabbit2:
    Examine Network Traffic (pp. 24-25)
    This section got me excited to learn about the data diffs being sent over the wire. I really liked how it encouraged you to actually open up your browser tools and look at the small footprint of the traffic. I read a previous forum post[1] and the the Phoenix.Socket.Message API[2] to help me dig deeper into understanding the network traffic.

    ["4","5","lv:phx-1YfONAIF",
    "event",{"type":"click","event":"guess",
    "value":{"number":"8"}}]
    

    Where I believe that:

    • “4” is the join_ref
    • “5” is the ref
    • “lv:phx-1Y…” is the topic

Great book and thank you for hosting this club!

[1] Shape of Phoenix Channel socket messages - #2 by kartheek
[2] Phoenix.Socket.Message — Phoenix v1.7.2

5 Likes

Thank you @Tbobbe and @olivegarden … some very interesting pointers on your reviews. It’ll certainly help us late readers

4 Likes

Chapter 4

Time to dive into the generated code for the frontend. There is quite a lot to take in from this chapter, so I will try to list my main takeaways:

  • handle_params(params, url, socket): This is the function that runs after mount. It is used to handle URL named parameters and live actions.
  • live actions: Used when one want to have a single live view handle multiple page states. In this case, listing, editing and creating product.
  • CoreComponents: A module with some fancy premade components ready to be used and/or modified. Learn the available core components for your own benefit! :smiley:
  • Attributes: Acts as named variables for your components, they are put inside the tag. Can be defined above the component definition using the attr macro.
  • Slots: Can be named or default to @inner_block. They are markup you put between the opening and closing tag of your component. Can be defined using the slot macro.
  • patch link: Changes the URL path and re-routes, but without changing the live view process. Perfect and effective when one want to move to a new live action within the same live view. Since no GET request is actually fired, mount will not be called, but we will get to handle_params instead.
  • Forms: When you see a form, think of changing data, which mean, think about Changesets. We use the validations defined in the Changeset to validate the form input! Smart!

I didn’t touch on functional components and live components since my list is already quite long, and they will get their own chapters.

Index.html.heex

I was actually quite surprised when I opened up the index.html.heex, and could not see a single normal HTML tag (actually, I later found one hiding in the table component). Now, all these concepts with components, attributes, slots etc. are great and super powerful, but at the same time I could see it feeling a bit daunting if you have done some HTML/CS/JS and some standard Elixir before, then you open up this file, and suddenly you can’t recognize a single thing.
This is not a criticism at all, just a thought about the experience of learning a new framework/DSL.

Outdated form

Unfortunately, the last part of the chapter regarding creating a new product using the form is a bit outdated. Not only syntax wise, but the logic has changed too.

In the book, they describe that the following happens when a product is saved: If the new product is successfully saved to the DB, we will navigate back to the product index page. This will trigger the mount function that will make a call to the DB, fetching all product in order to display the new one in the list.

The new generated code is much more efficient!
When the product is successfully sent to the DB, we will send the new product in a message to the parent using the notify_parent helper function. In the parent, this event is handled using a handle_info function (see index.ex). Since the list of products is implemented using a stream (also different from the book), the function simply inserts the new product into the stream. After this, we do a patch navigation to the product index page.

This results in 3 major gains (from what I can see):

  1. Since we use a stream, no data from the list of products is stored on the server, leading to gains in memory efficiency. This might not mean much in this small case, but think about the case when a list might contain thousands of items, and you have thousands of users using the site at the same time. Suddenly there is a lot of memory to be saved.
  2. Since we use patch instead of navigate, we don’t have to do a slow, pesky GET request. :smiley:
  3. Since we send the product from the child component to the parent directly, we don’t have to read a single entry from the database! (Once again, imagine if there were tens of thousands of products in the DB).

I’m sure the outdated code will be fixed for the final revision of the book. ^^

Overall, a great chapter which also makes multiple references to the CRC pattern. But you will probably have to go through it a couple of times in order to pick up on all the new information presented. Sorry for the long post :sweat_smile:.

6 Likes

Read the first two chapters and so far I have really enjoyed the pacing with a light introduction to Phoenix and going a bit deeper with CRC, Plug and the generated code.

It was also nice to get some more insight in how the LiveView lifecycle fits together with the normal control flow and live_session.

Really looking forward to the rest of the book.

2 Likes

I enjoyed reading the first chapters of the book. All was going well until I got the message function Bcrypt.no_user_verify/0 is undefined (module Bcrypt is not available which I am trying to reconcile. I am uncertain how to formally post a question.

1 Like

Maybe You did not load the dependencies after running mix phx.gen.auth…

That would be

mix deps.get

You can check if You have bcrypt_elixir in deps part of the mix.exs file

2 Likes

I checked the deps and actually ran mix deps.get and got the response

waynedavis@Waynes-MacBook-Pro pento % mix deps.get
Resolving Hex dependencies...
Resolution completed in 0.264s
Unchanged:
  bcrypt_elixir 3.0.1
  castore 1.0.1
  comeonin 5.3.3
  cowboy 2.9.0
  cowboy_telemetry 0.4.0
  cowlib 2.11.0
  db_connection 2.5.0
 ......

The code that is giving me problem is

  def valid_password?(_, _) do
    Bcrypt.no_user_verify()
    false
  end

in Pento.Accounts.User. I looked up Bcrypt in Hexdocs and saw that bcrypt_elixir 3.0.1 and Bcryp were addressed on the same page. However, I could not see how Bcrpt call would be referred to the Elixir program bcrypt_elixir 3.0.1. I checked to see if I might have missed inserting an “alias” somewhere. Every thing was going well upto this glitch.

As for me, my name is Wayne Davis. I am a 75 year-old emeritus professor in engineering. I returned to programming about a decade. I had lerned Fortran and Pascal, but had not programmed for decades. I initially learned Erlang and then migrated to Elixir. I tried to master Phoenix several times but always ran into unresolved issues. Recently I decided to give PhoenixLive a try. But again I hit a glitch. I appreciate any assistance.

4 Likes

After experimentation I got the following message after I entered the mix phi.server command

waynedavis@Waynes-MacBook-Pro pento % mix phx.server
[error] Failed to start Ranch listener PentoWeb.Endpoint.HTTP in :ranch_tcp:listen([cacerts: :..., key: :..., cert: :..., ip: {127, 0, 0, 1}, port: 4000]) for reason :eaddrinuse (address already in use)

[error] Running PentoWeb.Endpoint with cowboy 2.9.0 at http failed, port already in use
[notice] Application pento exited: Pento.Application.start(:normal, []) returned an error: shutdown: failed to start child: PentoWeb.Endpoint
    ** (EXIT) shutdown: failed to start child: {:ranch_listener_sup, PentoWeb.Endpoint.HTTP}
        ** (EXIT) shutdown: failed to start child: :ranch_acceptors_sup
            ** (EXIT) {:listen_error, PentoWeb.Endpoint.HTTP, :eaddrinuse}
[notice] Application plug_cowboy exited: :stopped
1 Like

Hi Davis!

As the error states, the application crashes since the port is already in use.
Normally, when I get this error, it’s because I already had the application or another phoenix app running on port 4000 in another shell or in the background.

Simply shut down the process that is hogging port 4000 and try again to start the application :slight_smile:

1 Like

You have all my respect.

For the issue, as mentioned in the previous post, there is already something running on port 4000.

When there is a compilation problem, You can try the following steps, from the root folder of the project.

rm -rf _build
mix compile

If You are unsure about deps, You can try

rm -rf deps
mix deps.get

There are also mix commands to help You clean the project. You can have the full list, or on a specific command

mix help
mix help <command>

bcrypt and bcrypt_elixir are not the same package. But it is unfortunate they share the same name. If You look at the doc…

https://hexdocs.pm/bcrypt_elixir/Bcrypt.html#content

You will see the package name is bcrypt_elixir, but the main module name is Bcrypt. It can be confusing

1 Like

I want to thank everyone for their replies. My bad. I was typing in localhost and the browser did an autofill which was taking me to the signup rather than the initial page at localhost:4000/guess. Anyway when I typed in the proper address it worked. Again thank you. By the way, I adopted Erlang/Elixir to support my former research in discrete-event simulation. The ability to perform concurrent computation upon thousands of independent trials is ideal. Additionally, I developed a new paradigm for the state evolution of discrete-event/task-execution systems which employs a regular grammar. The state can be represented by 2- or 4-tuples where each element itself can be either a numerical value or another tuple. The regular grammar is ideal for recursive functional programming.

Again thanks for your assistance.

Wayne

5 Likes

Any links to how this is being used in your research? I’d be curious to peek :smiley:

1 Like