After chapter 5 things are starting to gel. I’m now finding the ‘principle of least surprise’ applies:
"Hmm, I don’t like that validation error message. What if I add another parameter message: "my user friendly message? And it worked.
File upload functionality had some of the File API that looks a lot like Ruby’s, so again principle of least surprise
I can now work test-first more often. Tests for the Search page context were straight forward. Thanks to this forum I found the errors_on function in DataCase to write more readable and precise tests for error messages.
DRYing the validation for a 7 digit SKU was easy (extract function in Product and reuse that in ProductSearch.)
I skipped the image upload error handling exercise in Your Turn for now. I don’t need image uploads any time soon. It was fun to do the exercise in the chapter, as it gives more of a feel for handling state and working with files. Also, I want to skip ahead. I want to extract duplicate HTML in the search page. I copied the HTML from products/show and it looks like I need a function component for that, which is covered in the next chapter. Onward!
Partial answer: the wrong type for ‘content’ is a warning, it did show up somewhere in my iex session. Time to update emacs so it shows warnings in .heex files better.
This stackoverflow post recommends to run mix clean. mix clean followed by mix test clearly shows the warning with little noise:
mix test
Compiling 60 files (.ex)
warning: attribute "content" in component PentoWeb.SurveyLive.Component.hero/1 must be a :string, got: 123
lib/pento_web/live/survey_live.html.heex:2: (file)
Generated pento app
................................................................................................................................................................................................
Finished in 0.8 seconds (0.3s async, 0.5s sync)
192 tests, 0 failures
Randomized with seed 126290
Still not sure why I don’t get a warning about the empty @inner_block.
Decided to upgrade my emacs configuration, so that I could get compiler feedback when editing .heex.html files. After that, chapter 6 was wrapped up fairly quickly. I read ahead in chapter 7 and 8, the book continues to please with small steps and asking me questions about the trade-offs of various choices, and figuring out how things work under the hood, while at the same time working through what options for making things modular there are.
Yes, I just finished it! I have been occupied with other stuff, but figured it was time to give this book some more, well deserved, attention!
Chapter 6
A chapter about getting more familiar with function components and organizing code. Some takeaways:
I enjoyed the part about creating Query modules. Even tho the queries themselves were pretty simple, you got a good grasp of the project organization part of things. I was a bit unsure about having such a basic base() function on each query module, but after reading the argument about better refactoring, it made more sense!
Good and thorough content about everything related to functional components. Attributes and slots, neat! There was even a good explanation about the mysterious :let attribute in the tables :col slot.
The feeling I get overall is that function components are quite simple to start out with, but there is a lot of depth and power to them, which one can see by browsing the CoreComponents module.
In chapter 3, page 69 when running the tests, there are 2 additional tests failing, when having done
If a logged in user visits the / route, make them redirect to the /guess route (chapter 2, page 61)
The failing tests are:
test POST /users/log_in logs the user in (PentoWeb.UserSessionControllerTest)
test/pento_web/controllers/user_session_controller_test.exs:11
** (RuntimeError) expected response with status 200, got: 302, with body:
“You are being <a href="/guess">redirected.”
code: response = html_response(conn, 200)
stacktrace:
(phoenix 1.7.11) lib/phoenix/test/conn_test.ex:373: Phoenix.ConnTest.response/2
(phoenix 1.7.11) lib/phoenix/test/conn_test.ex:387: Phoenix.ConnTest.html_response/2
test/pento_web/controllers/user_session_controller_test.exs:22: (test)
…
test register user creates account and logs the user in (PentoWeb.UserRegistrationLiveTest)
test/pento_web/live/user_registration_live_test.exs:40
** (RuntimeError) expected response with status 200, got: 302, with body:
“You are being <a href="/guess">redirected.”
code: response = html_response(conn, 200)
stacktrace:
(phoenix 1.7.11) lib/phoenix/test/conn_test.ex:373: Phoenix.ConnTest.response/2
(phoenix 1.7.11) lib/phoenix/test/conn_test.ex:387: Phoenix.ConnTest.html_response/2
test/pento_web/live/user_registration_live_test.exs:58: (test)
So, they have nothing to do with the product template generator, but are caused by the redirect. This also regards to
Add a migration and a field to give the User schema a username field, and
display that username instead of the email address when a user logs in.
Did you require the username to be unique?
(chapter 2, page 61)
As in the tests the appereance of the email is tested.
Maybe a hint that the tests have to be adopted, where the exercises are given, would be helpful?
Consistent hints that tests have to be adopted would be helpfu indeedl. I thought there was a suggestion on devtalk already, but can’t find it. There are occasional suggestions in later chapters, but if one waits until then, there will be many other failing tests.
Because of duplication in generated tests, it is not that many fixes, but would be nicer to have regular reminders. I’ve adjusted to look at the tests at the end of each chapter, at the latest. I’ve also edited some tests to reduce duplicated steps.
In this chapter, we leveled up from function components to live components. The chapter does a good job in explaining what live components are and how they work. Some key takeaways:
I think it was good that the chapter did a little explanation about the preload callback for loading data from the DB in one call instead of many. Even though we did not use it. Very good knowledge to have if the situation arises.
The chapter really made a point about dividing the complexity into small chunks that can be worked on individually. I think the low friction involved in dividing a complex problem into simpler parts is one area where functional programming shines in general.
CRC pattern is back again!
I find the mental model of having the live view working almost as a supervisor for its live components quite nice. Only handling the setup and then the messages from the components, doing quite little else.
Some notes
Firstly, when writing the heex for the demographic survey, we defined a phx-update property on the form. This was not mentioned again or handled in the chapter, leading to a runtime error when trying out the demographic form. It was quite an easy fix though, drawing inspiration from previous code:
Secondly, I noticed that sometimes a code for a symbol would be used ★, and sometimes the symbol itself ★. In this case, I opted for just using the symbol directly.
Finally, when doing the second “Give it a try” exercise, in order to render any error below the rating option input, and still keeping the save button to the right, I inserted the .error function component into the rating form like so: