Skip to content

Cache related content #929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: 2024-upgrades-main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions app/controllers/concerns/action_page_display.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@ def set_action_display_variables
zipcode: current_zipcode,
country_code: current_country_code,
email: current_email }

@related_content = RelatedContent.new(@actionPage.related_content_url)
@related_content.load
end

def set_signatures
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/concerns/logged_invisible_captcha.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ module LoggedInvisibleCaptcha

def on_spam(options = {})
log_failure
super(options)
super
end

def on_timestamp_spam(options = {})
log_failure
super(options)
super
end

def log_failure
Expand Down
17 changes: 13 additions & 4 deletions app/lib/related_content.rb
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
class RelatedContent
def self.as_hash(url)
new(url).as_hash
end

def initialize(url)
@url = url
end

def as_hash
load unless found?
return unless found?
{ title: title, image_url: image }
end

def load
return if url.blank?

begin
open_page
@loaded_successfully = true
rescue OpenURI::HTTPError
rescue OpenURI::HttpError
nil
end
end

def found?
@loaded_successfully
!page.nil?
end

def title
Expand All @@ -35,7 +44,7 @@ def image

private

attr_reader :url, :page, :loaded_successfully
attr_reader :url, :page

def open_page
@page ||= Nokogiri::HTML(URI::open(url))
Expand Down
7 changes: 7 additions & 0 deletions app/models/action_page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,11 @@ def set_congress_tag

congress_message_campaign.update(campaign_tag: slug)
end

def related_content
key = "#{cache_key_with_version}/related_content"
Rails.cache.fetch(key, skip_nil: true) do
RelatedContent.as_hash(related_content_url)
end
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be good to let OpenURI::HTTPError bubble up out of RelatedContent and move the rescue to this method now, so that the {} value doesn't get cached in that case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ended up addressing this by changing RelatedContent to return nil in all fail states & used the skip_nil option on cache.fetch to avoid caching nil

end
21 changes: 21 additions & 0 deletions app/views/action_page/_related_content.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<div class="related-content">
<h4>Related Content</h4>
<%= link_to action_page.related_content_url do %>
<div class="image">
<%= image_tag(action_page.related_content[:image_url]) %>
</div>
<h5><%= action_page.related_content[:title] %></h5>
<% end %>
</div>
<div class="desc-text">
<p><%= markdown action_page.description -%></p>
</div>
<div class="related-content mobile">
<h4>Related Content</h4>
<%= link_to action_page.related_content_url do %>
<div class="image">
<%= image_tag(action_page.related_content[:image_url]) %>
</div>
<h5><%= action_page.related_content[:title] %></h5>
<% end %>
</div>
24 changes: 2 additions & 22 deletions app/views/action_page/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,8 @@
<input type='checkbox' style='display: none' id="learn-more">
<label for="learn-more">Learn More</label>
<div class="description" id="description">
<% if @related_content.found? %>
<div class="related-content">
<h4>Related Content</h4>
<%= link_to @actionPage.related_content_url do %>
<div class="image">
<%= image_tag(@related_content.image) %>
</div>
<h5><%= @related_content.title %></h5>
<% end %>
</div>
<div class="desc-text">
<p><%= markdown @actionPage.description -%></p>
</div>
<div class="related-content mobile">
<h4>Related Content</h4>
<%= link_to @actionPage.related_content_url do %>
<div class="image">
<%= image_tag(@related_content.image) %>
</div>
<h5><%= @related_content.title %></h5>
<% end %>
</div>
<% if @actionPage.related_content.present? %>
<%= render(partial: "related_content", locals: { action_page: @actionPage }) %>
<% else %>
<div class="desc-text full">
<p><%= markdown @actionPage.description -%></p>
Expand Down
2 changes: 1 addition & 1 deletion spec/features/ahoy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
end
end
end

def take_email_action(action_page)
visit action_page_path(action_page)
click_on "Use default mail client"
Expand Down
800 changes: 800 additions & 0 deletions spec/fixtures/files/deeplink.html

Large diffs are not rendered by default.

48 changes: 48 additions & 0 deletions spec/lib/related_content_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require "rails_helper"

RSpec.describe RelatedContent do
let(:stub_url) { "https://eff.org" }
let(:action_page) do
FactoryBot.create(:action_page, related_content_url: stub_url)
end
# these values are from the fixture
let(:og_image_url) { "https://www.eff.org/files/banner_library/robotai.png" }
let(:title) do
"California’s A.B. 412: A Bill That Could Crush Startups and Cement A "\
"Big Tech AI Monopoly"
end
subject { described_class.new(stub_url) }

before do
deeplink = file_fixture("deeplink.html").read
stub_request(:any, stub_url).to_return(body: deeplink)
end

describe "#load" do
it "fetches the html from the given URL" do
described_class.new(stub_url).load
expect(WebMock).to have_requested(:get, stub_url)
end
end

describe "#as_hash" do
it "returns the title and image url of the blogpost" do
expect(subject.as_hash).to eq({ title: title, image_url: og_image_url })
end
end

context "data methods" do
before { subject.load }
describe "#title" do
it "returns the blogpost title" do
expect(subject.title).to eq(title)
end
end

describe "#image" do
it "returns the blogpost og image url" do
expect(subject.image).to eq(og_image_url)
end
end
end
end
49 changes: 39 additions & 10 deletions spec/models/action_page_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,6 @@
expect(action_page.redirect_from_archived_to_active_action?).to be_truthy
end

# The test was a no-go because of the ajaxy html requiring nils... and Then
# changing them from nils to ""??? Needs effeciency review before crashyness review
# it "should not allow the creation of a model with so few attrs that it would crash the views" do
# expect {
# ActionPage.create!({ })
# }.to raise_exception(ActiveRecord::RecordInvalid)
#
# expect(ActionPage.count).to eq 0
# end

describe "slug" do
let(:page) { FactoryBot.create(:action_page) }
let(:new_slug) { "a-better-slug" }
Expand Down Expand Up @@ -192,4 +182,43 @@
end
end
end

describe "#related_content" do
include_context "with cache"
let(:url) { "related-content-url" }
let(:action_page) do
FactoryBot.create(:action_page, related_content_url: url)
end
let(:rc_hash) { { title: "Blog Title", image_url: "image-url" } }
let(:rc) do
class_double("RelatedContent")
.as_stubbed_const(transfer_nested_constants: true)
end
before { allow(rc).to receive(:as_hash).with(url).and_return(rc_hash) }

it "returns required data from the related content url" do
expect(action_page.related_content).to eq(rc_hash)
end

it "caches the hash" do
action_page.related_content
cache_key = "#{action_page.cache_key_with_version}/related_content"
expect(Rails.cache.fetch(cache_key)).to eq(rc_hash)
end

it "doesn't hit RelatedContent when cached" do
action_page.related_content
expect(rc).not_to receive(:as_hash)
action_page.related_content
end

it "cache becomes stale when the model is updated" do
action_page.related_content
new_url = "new-url"
new_hash = { title: "New", image_url: "new-image-url" }
action_page.update(related_content_url: "new-url")
allow(rc).to receive(:as_hash).with(new_url).and_return(new_hash)
expect(action_page.reload.related_content).to eq(new_hash)
end
end
end
8 changes: 8 additions & 0 deletions spec/support/cache_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
RSpec.shared_context "with cache", :with_cache do
let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) }

before do
allow(Rails).to receive(:cache).and_return(memory_store)
Rails.cache.clear
end
end