Skip to content
Merged
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
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ gem 'turbo-rails'
# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem 'stimulus-rails'
gem 'public_activity'
gem 'view_component'

group :development do
gem 'better_errors'
Expand Down
5 changes: 5 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,10 @@ GEM
uri (1.1.1)
useragent (0.16.11)
version_gem (1.1.3)
view_component (4.5.0)
actionview (>= 7.1.0)
activesupport (>= 7.1.0)
concurrent-ruby (~> 1)
web-console (4.2.1)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
Expand Down Expand Up @@ -694,6 +698,7 @@ DEPENDENCIES
timecop (~> 0.9.10)
turbo-rails
tzinfo-data
view_component
web-console (>= 4.1.0)
webmock

Expand Down
12 changes: 12 additions & 0 deletions app/components/chapters_sidebar_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<% cache "chapters-sidebar" do %>
<% if title %>
<h3><%= title %></h3>
<% end %>
<ul class="list-unstyled ms-0">
<% chapters.each do |chapter| %>
<li>
<%= link_to chapter.name, chapter_path(chapter.slug) %>
</li>
<% end %>
</ul>
<% end %>
13 changes: 13 additions & 0 deletions app/components/chapters_sidebar_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

class ChaptersSidebarComponent < ViewComponent::Base
# ViewComponent::Base does not define initialize, so super is not needed
def initialize(chapters:, title: nil) # rubocop:disable Lint/MissingSuper
@chapters = chapters
@title = title
end

private

attr_reader :chapters, :title
end
7 changes: 7 additions & 0 deletions app/models/chapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ class Chapter < ApplicationRecord
has_many :feedbacks, through: :workshops

before_save :set_slug
after_update_commit :expire_chapters_sidebar_cache
after_create_commit :expire_chapters_sidebar_cache
after_destroy_commit :expire_chapters_sidebar_cache

scope :active, -> { where(active: true) }

Expand Down Expand Up @@ -47,6 +50,10 @@ def coaches

private

def expire_chapters_sidebar_cache
Rails.cache.delete('chapters-sidebar')
end

def time_zone_exists
return unless time_zone && ActiveSupport::TimeZone[time_zone].nil?

Expand Down
7 changes: 1 addition & 6 deletions app/views/dashboard/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,7 @@
= link_to 'Explore all events →', upcoming_events_path, class: 'btn btn-outline-primary mt-3'

.col-lg-4.pl-lg-5
%h3
= t('homepage.chapters.title')
%ul.list-unstyled.ms-0
- @chapters.each do |chapter|
%li
= link_to chapter.name, chapter_path(chapter.slug)
= render ChaptersSidebarComponent.new(chapters: @chapters, title: t('homepage.chapters.title'))

- if @testimonials.any?
.py-4.py-lg-5.bg-light
Expand Down
24 changes: 24 additions & 0 deletions spec/components/chapters_sidebar_component_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
require 'rails_helper'
require 'view_component/test_helpers'

RSpec.describe ChaptersSidebarComponent do
include ViewComponent::TestHelpers
include Rails.application.routes.url_helpers

let(:chapters) { Fabricate.times(3, :chapter) }

it 'renders chapter names as links' do
render_inline ChaptersSidebarComponent.new(chapters: chapters)

chapters.each do |chapter|
expect(page).to have_link(chapter.name, href: chapter_path(chapter.slug))
end
end

it 'renders nothing when no chapters' do
render_inline ChaptersSidebarComponent.new(chapters: [])

expect(page).to have_css('ul.list-unstyled.ms-0', visible: true)
expect(page).to have_no_css('li')
end
end
24 changes: 24 additions & 0 deletions spec/models/chapter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,28 @@
end
end
end

context 'cache expiration' do
let(:cache_key) { 'chapters-sidebar' }

it 'expires cache when chapter is created' do
Rails.cache.write(cache_key, 'cached content')
Fabricate(:chapter)
expect(Rails.cache.read(cache_key)).to be_nil
end

it 'expires cache when chapter is updated' do
Rails.cache.write(cache_key, 'cached content')
chapter = Fabricate(:chapter)
chapter.update!(name: 'Updated Name')
expect(Rails.cache.read(cache_key)).to be_nil
end

it 'expires cache when chapter is destroyed' do
Rails.cache.write(cache_key, 'cached content')
chapter = Fabricate(:chapter)
chapter.destroy
expect(Rails.cache.read(cache_key)).to be_nil
end
end
end
45 changes: 45 additions & 0 deletions spec/rails_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
# Prevent database truncation if the environment is production
abort('The Rails environment is running in production mode!') if Rails.env.production?
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!

# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_helper.rb` can
# be required explicitly.
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

# Checks for pending migration and applies them before tests are run.
# If you are not using ActiveRecord, you can remove these lines.
begin
ActiveRecord::Migration.check_all_pending!
rescue ActiveRecord::PendingMigrationError => e
puts e.to_s.strip
exit 1
end
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_paths = ["#{::Rails.root}/spec/fixtures"]

# If you're not using ActiveRecord, or you'd prefer not to use each of your
# test frameworks (like Capybara or Selenium) for test
# see https://relishapp.com/rspec/rspec-rails/docs/configuration
config.use_transactional_fixtures = true

# RSpec Rails can automatically mix in different behaviours based on the
# file location of the spec. This line needs to be present for ViewComponent
# to work with controller specs
config.infer_spec_type_from_file_location!

# Connect ViewComponent to RSpec, adding RSpec metadata type: :component.
# This extends Rails' own built-in (e.g. "type: :controller") metadata system.
RSpec::Rails::DIRECTORY_MAPPINGS[:component] = %w[spec/components]

# Filter lines from Rails gems in backtraces.
config.filter_rails_from_backtrace!
# arbitrary gems may also be filtered from backtraces
# this line is optional and should be present if your application depends
# on external gems, but this is not needed for ViewComponent tests
end
13 changes: 0 additions & 13 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,6 @@ def self.branch_coverage?

# See https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example
config.before(:suite) do
if config.use_transactional_fixtures?
raise(<<-MSG)
Delete line `config.use_transactional_fixtures = true` from spec_helper.rb
(or set it to false) to prevent uncommitted transactions being used in
JavaScript-dependent specs.

During testing, the app-under-test that the browser driver connects to
uses a different database connection to the database connection used by
the spec. The app's database connection would not be able to access
uncommitted transaction data setup over the spec's database connection.
MSG
end

DatabaseCleaner.clean_with(:truncation)
DatabaseCleaner.strategy = :deletion
end
Expand Down
22 changes: 22 additions & 0 deletions spec/views/dashboard/show.html.haml_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
require 'rails_helper'

RSpec.describe 'dashboard/show.html.haml', type: :view do
let(:chapters) { Fabricate.times(2, :chapter) }
let(:upcoming_workshops) { {} }
let(:testimonials) { [] }

before do
assign(:chapters, chapters)
assign(:upcoming_workshops, upcoming_workshops)
assign(:has_more_events, false)
assign(:testimonials, testimonials)
render
end

it 'renders the chapters sidebar component' do
expect(rendered).to have_selector('.col-lg-4.pl-lg-5')
chapters.each do |chapter|
expect(rendered).to have_link(chapter.name, href: chapter_path(chapter.slug))
end
end
end