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

Alexandr
Hi everyone! There is an error on the page 71 in the book “Programming machine learning from coding to depp learning” P. Perrotta. You c...
New
mikecargal
Title: Hands-On Rust (Chapter 11: prefab) Just played a couple of amulet-less games. With a bit of debugging, I believe that your can_p...
New
raul
Page 28: It implements io.ReaderAt on the store type. Sorry if it’s a dumb question but was the io.ReaderAt supposed to be io.ReadAt? ...
New
AleksandrKudashkin
On the page xv there is an instruction to run bin/setup from the main folder. I downloaded the source code today (12/03/21) and can’t see...
New
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
jskubick
I’m under the impression that when the reader gets to page 136 (“View Data with the Database Inspector”), the code SHOULD be able to buil...
New
New
redconfetti
Docker-Machine became part of the Docker Toolbox, which was deprecated in 2020, long after Docker Desktop supported Docker Engine nativel...
New

Other popular topics Top

Devtalk
Reading something? Working on something? Planning something? Changing jobs even!? If you’re up for sharing, please let us know what you’...
1052 22283 402
New
siddhant3030
I’m thinking of buying a monitor that I can rotate to use as a vertical monitor? Also, I want to know if someone is using it for program...
New
DevotionGeo
I know that -t flag is used along with -i flag for getting an interactive shell. But I cannot digest what the man page for docker run com...
New
AstonJ
This looks like a stunning keycap set :orange_heart: A LEGENDARY KEYBOARD LIVES ON When you bought an Apple Macintosh computer in the e...
New
PragmaticBookshelf
Tailwind CSS is an exciting new CSS framework that allows you to design your site by composing simple utility classes to create complex e...
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
AstonJ
We’ve talked about his book briefly here but it is quickly becoming obsolete - so he’s decided to create a series of 7 podcasts, the firs...
New
First poster: bot
zig/http.zig at 7cf2cbb33ef34c1d211135f56d30fe23b6cacd42 · ziglang/zig. General-purpose programming language and toolchain for maintaini...
New
AstonJ
If you’re getting errors like this: psql: error: connection to server on socket “/tmp/.s.PGSQL.5432” failed: No such file or directory ...
New
PragmaticBookshelf
Get the comprehensive, insider information you need for Rails 8 with the new edition of this award-winning classic. Sam Ruby @rubys ...
New

Sub Categories: