Skip to content

Commit

Permalink
Add Category list method
Browse files Browse the repository at this point in the history
Add a method to return a flat list of categories for a given root. This
will be useful in places as this replicates to functionality of the
older `PublicBodyCategory` model.

Fixes #8081
  • Loading branch information
gbp committed Jan 9, 2024
1 parent ed989c4 commit b5986fa
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 7 deletions.
2 changes: 1 addition & 1 deletion app/helpers/public_body_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def public_body_not_requestable_reasons(public_body)
#
# Returns a String
def type_of_authority(public_body)
categories = PublicBody.categories.
categories = PublicBody.category_list.
where(category_tag: public_body.tag_string.split).order(:id)

types = categories.each_with_index.map do |category, index|
Expand Down
21 changes: 21 additions & 0 deletions app/models/category.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,27 @@ def tree
children.includes(:translations, children: [:translations])
end

def list
sql = <<~SQL.squish
WITH RECURSIVE nested_categories AS (
SELECT child_id
FROM category_relationships
WHERE parent_id = :parent_id
UNION ALL
SELECT cr.child_id
FROM category_relationships cr
INNER JOIN nested_categories nc ON cr.parent_id = nc.child_id
)
SELECT DISTINCT c.id FROM categories c
INNER JOIN nested_categories nc ON c.id = nc.child_id;
SQL

ids = Category.find_by_sql([sql, { parent_id: id }]).map(&:id)
Category.where(id: ids).includes(:translations)
end

private

def check_tag_assignments
Expand Down
4 changes: 4 additions & 0 deletions app/models/concerns/categorisable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@ def self.category_root
def self.categories
category_root.tree
end

def self.category_list
category_root.list
end
end
end
10 changes: 5 additions & 5 deletions spec/helpers/public_body_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,11 @@
expect(type_of_authority(public_body)).to eq(expected)
end

context 'when associated with one category' do
context 'when categories are descendents of non-root parents' do
it 'returns the description wrapped in an anchor tag' do
FactoryBot.create(
:category, :public_body,
:category,
parents: [FactoryBot.build(:category, :public_body)],
category_tag: 'spec',
description: 'spec category'
)
Expand All @@ -94,13 +95,12 @@
anchor = %Q(<a href="/body/list/spec">Spec category</a>)
expect(type_of_authority(public_body)).to eq(anchor)
end
end

context 'when associated with several categories' do
it 'joins the category descriptions and capitalizes the first letter' do
3.times do |i|
FactoryBot.create(
:category, :public_body,
:category,
parents: [FactoryBot.build(:category, :public_body)],
category_tag: "spec_#{i}",
description: "spec category #{i}"
)
Expand Down
57 changes: 56 additions & 1 deletion spec/models/category_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@
FactoryBot.create(:category, title: 'Branch', parents: [trunk])
end

let!(:other_root) do
FactoryBot.create(:category, title: 'InfoRequest')
end

let!(:other_trunk) do
FactoryBot.create(:category, title: 'Trunk', parents: [other_root])
end

around do |example|
@query_count = 0
subscription = ActiveSupport::Notifications.subscribe(
Expand All @@ -141,7 +149,7 @@
ActiveSupport::Notifications.unsubscribe(subscription)
end

it 'returns root category descendents' do
it 'returns root category descendents as tree' do
expect(root.tree).to match_array([trunk])
expect(root.tree[0].children).to match_array([branch])
end
Expand All @@ -159,4 +167,51 @@
}.to_not change { @query_count }
end
end

describe '#list' do
subject { root.list }

let!(:root) do
FactoryBot.create(:category, title: 'PublicBody')
end

let!(:trunk) do
FactoryBot.create(:category, title: 'Trunk', parents: [root])
end

let!(:branch) do
FactoryBot.create(:category, title: 'Branch', parents: [trunk])
end

let!(:other_root) do
FactoryBot.create(:category, title: 'InfoRequest')
end

let!(:other_trunk) do
FactoryBot.create(:category, title: 'Trunk', parents: [other_root])
end

around do |example|
@query_count = 0
subscription = ActiveSupport::Notifications.subscribe(
'sql.active_record'
) { @query_count += 1 }

example.call

ActiveSupport::Notifications.unsubscribe(subscription)
end

it 'returns root category descendents as list' do
expect(root.list).to match_array([trunk, branch])
end

it 'preload translations' do
# load list and perform all necessary DB queries
list = root.list.to_a

# iterate through list and ensure translations have been preloaded
expect { list.each(&:title) }.to_not change { @query_count }
end
end
end
7 changes: 7 additions & 0 deletions spec/models/concerns/categorisable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,11 @@
described_class.categories
end
end

describe '.category_list' do
it 'calls category_root.list' do
expect(described_class).to receive_message_chain(:category_root, :list)
described_class.category_list
end
end
end

0 comments on commit b5986fa

Please sign in to comment.