Setting an etag based on ActiveRecord objects + arbitrary values via fresh_when in Rails 8

I am using code like this to compute a composite cache_key from arbitrary values and ActiveRecord objects (basically everything that’s used to build the page) in Rails controllers to enable browser-side caching:

cache_key = [site_cache_key, all_events, all_locations].flatten
fresh_when cache_key

(site_cache_key is a string that changes with the commit id of the repo so all template changes are covered, I remember having lots of problems with stale pages when partials were involved, so I went for a simple “invalidate everything when a new version is released”)

This worked fine in Rails 6, but fails in Rails 8 (might also have changed in Rails 7 already):

undefined method 'updated_at' for an instance of String

I am wondering, was this change intentional / should this be supported / is there is a better way to set an etag based from a mix of activerecord objects and arbitrary values?

As a workaround, I am using this:

cache_key = [site_cache_key, all_events, all_locations, some_other_value].flatten
fresh_when(etag: cache_key, last_modified: cache_key.map { |e| e.try(:updated_at) }.compact.max)

You need to check what fresh_when does with the etag variable under the hood. You may need to wrap the values you give it with some kind of delegator which either forwards cache_key if the object or collection supports it, or something of that nature. If you look at the complete backtrace it will show you where updated_at is called and on what.