Skip to content

Commit

Permalink
Use page version's updated_at timestamp as cache key
Browse files Browse the repository at this point in the history
Currently, it's hard for us to invalidate caches for Alchemy pages when
content that's referenced through ingredients with related objects
changes.

For example, in a situation where a user combines Alchemy and Solidus
using the `alchemy_solidus` gem, a page's cache key does not update when
a product that's referenced through a SpreeProduct ingredient changes.

There's a PR up on the alchemy_solidus gem that touches ingredients in
these situations, and with this change, that touching can be used for
breaking caches. [1]

In the unlikely event the requested version is not available, we use the
page's updated_at timestamp as a fallback.

[1](AlchemyCMS/alchemy-solidus#108)
  • Loading branch information
mamhoff committed May 8, 2024
1 parent cbef269 commit c3ab762
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 10 deletions.
15 changes: 6 additions & 9 deletions app/models/alchemy/page/page_natures.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,15 @@ def layout_partial_name
page_layout.parameterize.underscore
end

# Returns the version that's taken for Rails' recycable cache key.
# Returns the string version that's used as Rails' recycable cache key.
#
# Uses the +published_at+ value that's updated when the user publishes the page.
#
# If the page is the current preview it uses the +updated_at+ value as cache key.
# In preview mode, it will take the draft version's updated_at timestamp.
# In public mode, it will take the public version's updated_at timestamp.
# If no version is available, it will take the page's updated_at timestamp.
#
def cache_version
if Current.preview_page == self
updated_at.to_s
else
published_at.to_s
end
relevant_page_version = (Current.preview_page == self) ? draft_version : public_version
(relevant_page_version&.updated_at || updated_at).to_s
end

# Returns true if the page cache control headers should be set.
Expand Down
34 changes: 33 additions & 1 deletion spec/models/alchemy/page_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -705,12 +705,16 @@ module Alchemy

describe "#cache_version" do
let(:now) { Time.current }
let(:yesterday) { Time.current - 1.day }
let(:last_week) { Time.current - 1.week }

let(:page) do
build_stubbed(:alchemy_page, updated_at: now, published_at: last_week)
build_stubbed(:alchemy_page, public_version: public_version, draft_version: draft_version, updated_at: yesterday)
end

let(:public_version) { build_stubbed(:alchemy_page_version, updated_at: last_week) }
let(:draft_version) { build_stubbed(:alchemy_page_version, updated_at: now) }

subject { page.cache_version }

before do
Expand All @@ -732,6 +736,34 @@ module Alchemy
is_expected.to eq(last_week.to_s)
end
end

context "if page has no public version" do
let(:public_version) { nil }

context "in preview mode" do
let(:preview) { page }

it "uses updated_at" do
is_expected.to eq(now.to_s)
end

context "if page has no draft version" do
let(:draft_version) { nil }

it "returns nil" do
is_expected.to eq(yesterday.to_s)
end
end
end

context "not in preview mode" do
let(:preview) { nil }

it "uses updated_at" do
is_expected.to eq(yesterday.to_s)
end
end
end
end

describe "#public_version" do
Expand Down

0 comments on commit c3ab762

Please sign in to comment.