Cellane

Cellane

Agile Web Development with Rails 8: live product refresh not working in chapter 11

Hello, I was struggling a bit with completing chapter 11, iteration F4.

While the changes done in the “admin” (maintenance?) panel to store products showed up without me refreshing the main store page, it didn’t feel as smooth as it should have – the entire page refreshed, instead of just morphing the DOM to contain the new data. After spending a few hours investigating this, I found two root causes that should probably be addressed in the final book:

The entire rendering process is crashing due to not being able to render the product partial

This issue can be observed either from the terminal, where I could see this output (truncated):

02:38:35 web.1  | Started GET "/products/7" for ::1 at 2025-02-20 02:38:35 +0900
02:38:35 web.1  | [ActiveJob] [Turbo::Streams::ActionBroadcastJob] [40cc8022-d8d7-4b62-9fcb-053676ba5413]   Product Load (0.2ms)  SELECT "products".* FROM "products" WHERE "products"."id" = 7 LIMIT 1 /*application='Depot'*/
02:38:35 web.1  | [ActiveJob] [Turbo::Streams::ActionBroadcastJob] [40cc8022-d8d7-4b62-9fcb-053676ba5413] Performing Turbo::Streams::ActionBroadcastJob (Job ID: 40cc8022-d8d7-4b62-9fcb-053676ba5413) from Async(default) enqueued at 2025-02-19T17:38:35.448256000Z with arguments: "products", {action: :replace, target: "product_7", targets: nil, attributes: {}, partial: "store/product", locals: {product: #<GlobalID:0x0000000138317188 @uri=#<URI::GID gid://depot/Product/7>>}}
02:38:35 web.1  | [ActiveJob] [Turbo::Streams::ActionBroadcastJob] [40cc8022-d8d7-4b62-9fcb-053676ba5413]   ActiveStorage::Attachment Load (0.1ms)  SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = 7 AND "active_storage_attachments"."record_type" = 'Product' AND "active_storage_attachments"."name" = 'image' LIMIT 1 /*application='Depot',job='Turbo%3A%3AStreams%3A%3AActionBroadcastJob'*/
02:38:35 web.1  | [ActiveJob] [Turbo::Streams::ActionBroadcastJob] [40cc8022-d8d7-4b62-9fcb-053676ba5413]   ↳ app/views/store/_product.html.erb:3
02:38:35 web.1  | [ActiveJob] [Turbo::Streams::ActionBroadcastJob] [40cc8022-d8d7-4b62-9fcb-053676ba5413]   ActiveStorage::Blob Load (0.0ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = 7 LIMIT 1 /*application='Depot',job='Turbo%3A%3AStreams%3A%3AActionBroadcastJob'*/
02:38:35 web.1  | [ActiveJob] [Turbo::Streams::ActionBroadcastJob] [40cc8022-d8d7-4b62-9fcb-053676ba5413]   ↳ app/views/store/_product.html.erb:3
02:38:35 web.1  | [ActiveJob] [Turbo::Streams::ActionBroadcastJob] [40cc8022-d8d7-4b62-9fcb-053676ba5413]   Disk Storage (0.9ms) Generated URL for file at key: v7g25mgxk84oj9sxzjdpjyafgygx ()
02:38:35 web.1  | [ActiveJob] [Turbo::Streams::ActionBroadcastJob] [40cc8022-d8d7-4b62-9fcb-053676ba5413]   Rendered store/_product.html.erb (Duration: 7.0ms | GC: 0.0ms)
02:38:35 web.1  | [ActiveJob] [Turbo::Streams::ActionBroadcastJob] [40cc8022-d8d7-4b62-9fcb-053676ba5413] Error performing Turbo::Streams::ActionBroadcastJob (Job ID: 40cc8022-d8d7-4b62-9fcb-053676ba5413) from Async(default) in 12.4ms: ActionView::Template::Error (Cannot generate URL for nrclient2.jpg using Disk service, please set ActiveStorage::Current.url_options.):
02:38:35 web.1  | /Users/milan/.local/share/mise/installs/ruby/3.4.1/lib/ruby/gems/3.4.0/gems/activestorage-8.0.1/lib/active_storage/service/disk_service.rb:138:in 'ActiveStorage::Service::DiskService#generate_url'
02:38:35 web.1  | /Users/milan/.local/share/mise/installs/ruby/3.4.1/lib/ruby/gems/3.4.0/gems/activestorage-8.0.1/lib/active_storage/service/disk_service.rb:117:in 'ActiveStorage::Service::DiskService#private_url'
02:38:35 web.1  | /Users/milan/.local/share/mise/installs/ruby/3.4.1/lib/ruby/gems/3.4.0/gems/activestorage-8.0.1/lib/active_storage/service.rb:125:in 'block in ActiveStorage::Service#url'
02:38:35 web.1  | /Users/milan/.local/share/mise/installs/ruby/3.4.1/lib/ruby/gems/3.4.0/gems/activesupport-8.0.1/lib/active_support/notifications.rb:210:in 'block in ActiveSupport::Notifications.instrument'
02:38:35 web.1  | /Users/milan/.local/share/mise/installs/ruby/3.4.1/lib/ruby/gems/3.4.0/gems/activesupport-8.0.1/lib/active_support/notifications/instrumenter.rb:58:in 'ActiveSupport::Notifications::Instrumenter#instrument'

Or in the browser’s developer console, where you can see the store main page unsubscribing from the WebSocket topic and resubscribing back to it – which should not happen. Also, the entire page just very obviously jumps, as it would if there was a full page reload happening.

Based on the error message, I thought that something akin to include ActiveStorage::SetCurrent that we previously added to ApplicationController also needs to be added to ApplicationCable::Channel but that doesn’t seem to be the case, as the solution is much simpler – the store/_product partial needs to be changed instead:

-    <%= image_tag(product.image.url, class: "object-contain w-40 h-48 shadow mr-6") %>
+    <%= image_tag(product.image, class: "object-contain w-40 h-48 shadow mr-6") %>

After this, the crash no longer happens in the server console, but the page still hard-refreshes. That’s because…

The WebSockets topics overlap with chapter 6

Chapter 6 adds after_commit -> { broadcast_refresh_later_to "products" }, introducing the products topic, and then chapter 11 reuses the topic to broadcast not the information to refresh the page, but to replace the affected part. I think these should not share the same topic, so after changing ProductsChannel like so:

-    stream_from "products"
+    stream_from "store/products"

ProductsController like so:

-        @product.broadcast_replace_later_to "products", partial: "store/product"
+        @product.broadcast_replace_later_to "store/products", partial: "store/product"

… and store’s view template like so:

- <%= turbo_stream_from "products" %>
+ <%= turbo_stream_from "store/products" %>

… everything starts working smoothly again, no full-page refreshes happen, and only the affected product gets replaced.

That was a fun one to figure out, as a Rails newbie! :face_with_hand_over_mouth:

(Also I feel like earlier in the chapter, the customer said to please honour the price of the product at the time of adding the product to the cart and I don’t think that’s happening yet but maybe it will be addressed later in the chapter…? Or maybe just not written yet, should probably involve putting the price on LineItem and copying the value over at the time of adding it to the cart.) I missed that this is part of the optional exercises on pages 144~145. My bad!

Marked As Solved

rubys

rubys

Author of Agile Web Development With Rails

Good catch, and good suggestion! And glad you are having fun! Thanks!

Where Next?

Popular Pragmatic Bookshelf topics Top

jimmykiang
This test is broken right out of the box… — FAIL: TestAgent (7.82s) agent_test.go:77: Error Trace: agent_test.go:77 agent_test.go:...
New
New
GilWright
Working through the steps (checking that the Info,plist matches exactly), run the demo game and what appears is grey but does not fill th...
New
JohnS
I can’t setup the Rails source code. This happens in a working directory containing multiple (postgres) Rails apps. With: ruby-3.0.0 s...
New
HarryDeveloper
Hi @venkats, It has been mentioned in the description of ‘Supervisory Job’ title that 2 things as mentioned below result in the same eff...
New
leonW
I ran this command after installing the sample application: $ cards add do something --owner Brian And got a file not found error: Fil...
New
AndyDavis3416
@noelrappin Running the webpack dev server, I receive the following warning: ERROR in tsconfig.json TS18003: No inputs were found in c...
New
jskubick
I’m running Android Studio “Arctic Fox” 2020.3.1 Patch 2, and I’m embarrassed to admit that I only made it to page 8 before running into ...
New
davetron5000
Hello faithful readers! If you have tried to follow along in the book, you are asked to start up the dev environment via dx/build and ar...
New
roadbike
From page 13: On Python 3.7, you can install the libraries with pip by running these commands inside a Python venv using Visual Studio ...
New

Other popular topics Top

dasdom
No chair. I have a standing desk. This post was split into a dedicated thread from our thread about chairs :slight_smile:
New
brentjanderson
Bought the Moonlander mechanical keyboard. Cherry Brown MX switches. Arms and wrists have been hurting enough that it’s time I did someth...
New
AstonJ
Just done a fresh install of macOS Big Sur and on installing Erlang I am getting: asdf install erlang 23.1.2 Configure failed. checking ...
New
AstonJ
I have seen the keycaps I want - they are due for a group-buy this week but won’t be delivered until October next year!!! :rofl: The Ser...
New
Rainer
Not sure if following fits exactly this thread, or if we should have a hobby thread… For many years I’m designing and building model air...
New
PragmaticBookshelf
“A Mystical Experience” Hero’s Journey with Paolo Perrotta @nusco Ever wonder how authoring books compares to writing articles?...
New
Margaret
Hello everyone! This thread is to tell you about what authors from The Pragmatic Bookshelf are writing on Medium.
1139 25652 757
New
foxtrottwist
A few weeks ago I started using Warp a terminal written in rust. Though in it’s current state of development there are a few caveats (tab...
New
PragmaticBookshelf
Author Spotlight: VM Brasseur @vmbrasseur We have a treat for you today! We turn the spotlight onto Open Source as we sit down with V...
New
CommunityNews
A Brief Review of the Minisforum V3 AMD Tablet. Update: I have created an awesome-minisforum-v3 GitHub repository to list information fo...
New

Sub Categories: