diff --git a/app/controllers/admin/categories_controller.rb b/app/controllers/admin/categories_controller.rb
index 93ec162b4e..73e1599e94 100644
--- a/app/controllers/admin/categories_controller.rb
+++ b/app/controllers/admin/categories_controller.rb
@@ -4,6 +4,7 @@
class Admin::CategoriesController < AdminController
include TranslatableParams
+ before_action :check_klass
before_action :set_root, expect: [:destroy, :reorder]
before_action :set_category, only: [:edit, :update, :destroy, :reorder]
@@ -19,7 +20,7 @@ def create
@category = Category.new(category_params)
if @category.save
flash[:notice] = 'Category was successfully created.'
- redirect_to admin_categories_path
+ redirect_to admin_categories_path(model_type: current_klass)
else
@category.build_all_translations
render action: 'new'
@@ -33,7 +34,7 @@ def edit
def update
if @category.update(category_params)
flash[:notice] = 'Category was successfully updated.'
- redirect_to admin_categories_path
+ redirect_to admin_categories_path(model_type: current_klass)
else
@category.build_all_translations
render action: 'edit'
@@ -43,7 +44,7 @@ def update
def destroy
@category.destroy
flash[:notice] = 'Category was successfully destroyed.'
- redirect_to admin_categories_path
+ redirect_to admin_categories_path(model_type: current_klass)
end
def reorder
@@ -82,10 +83,19 @@ def category_params
end
def set_root
- @root = Category.public_body_root
+ @root = current_klass.category_root
end
def set_category
@category = Category.find(params[:id])
end
+
+ helper_method :current_klass
+ def current_klass
+ params.fetch(:model_type, 'PublicBody').safe_constantize
+ end
+
+ def check_klass
+ raise RouteNotFound unless Categorisable.models.include?(current_klass)
+ end
end
diff --git a/app/models/category.rb b/app/models/category.rb
index d175aa9640..3ba777ae85 100644
--- a/app/models/category.rb
+++ b/app/models/category.rb
@@ -49,10 +49,6 @@ class Category < ApplicationRecord
joins(:parent_relationships).where(parent_relationships: { parent: parent })
end
- def self.public_body_root
- Category.roots.find_or_create_by(title: 'PublicBody')
- end
-
def tree
children.includes(:translations, children: [:translations])
end
diff --git a/app/models/concerns/categorisable.rb b/app/models/concerns/categorisable.rb
new file mode 100644
index 0000000000..95b9ac96d0
--- /dev/null
+++ b/app/models/concerns/categorisable.rb
@@ -0,0 +1,22 @@
+##
+# Module concern with methods to help categorise records
+#
+module Categorisable
+ extend ActiveSupport::Concern
+
+ def self.models
+ @models ||= []
+ end
+
+ included do
+ Categorisable.models << self
+
+ def self.category_root
+ Category.roots.find_or_create_by(title: name)
+ end
+
+ def self.categories
+ category_root.tree
+ end
+ end
+end
diff --git a/app/models/info_request.rb b/app/models/info_request.rb
index 59b63197a3..8f1ede4157 100644
--- a/app/models/info_request.rb
+++ b/app/models/info_request.rb
@@ -49,6 +49,7 @@ class InfoRequest < ApplicationRecord
include InfoRequest::PublicToken
include InfoRequest::Sluggable
include InfoRequest::TitleValidation
+ include Categorisable
include Taggable
include Notable
include LinkToHelper
diff --git a/app/models/public_body.rb b/app/models/public_body.rb
index 68d651d18f..151a9aeb96 100644
--- a/app/models/public_body.rb
+++ b/app/models/public_body.rb
@@ -33,6 +33,7 @@
class PublicBody < ApplicationRecord
include CalculatedHomePage
+ include Categorisable
include Taggable
include Notable
include Rails.application.routes.url_helpers
diff --git a/app/views/admin/categories/_scope.html.erb b/app/views/admin/categories/_scope.html.erb
new file mode 100644
index 0000000000..613859a2b3
--- /dev/null
+++ b/app/views/admin/categories/_scope.html.erb
@@ -0,0 +1,7 @@
+
+ <% Categorisable.models.sort_by(&:admin_title).each do |klass| %>
+ <%= tag.li class: { active: current_klass == klass } do %>
+ <%= link_to klass.admin_title.pluralize, url_for(model_type: klass.name, query: params[:query]) %>
+ <% end %>
+ <% end %>
+
diff --git a/app/views/admin/categories/edit.html.erb b/app/views/admin/categories/edit.html.erb
index a7c46098c8..a4254d1925 100644
--- a/app/views/admin/categories/edit.html.erb
+++ b/app/views/admin/categories/edit.html.erb
@@ -5,13 +5,15 @@
diff --git a/app/views/admin/categories/index.html.erb b/app/views/admin/categories/index.html.erb
index a082bf5ee1..ef26fed394 100644
--- a/app/views/admin/categories/index.html.erb
+++ b/app/views/admin/categories/index.html.erb
@@ -1,10 +1,12 @@
-<% @title = 'Listing public authority categories' %>
+<% @title = "Listing #{current_klass.admin_title} categories" %>
<%=@title%>
+<%= render partial: 'scope' %>
+
@@ -21,7 +23,7 @@
<%= heading.children.size %>
<%= chevron_right %>
-
<%= link_to(heading.title, edit_admin_category_path(heading), title: "view full details") %>
+
<%= link_to(heading.title, edit_admin_category_path(heading, model_type: current_klass), title: "view full details") %>
@@ -34,7 +36,7 @@
<% end %>
- <%= link_to(category.title, edit_admin_category_path(category), title: "view full details") %>
+ <%= link_to(category.title, edit_admin_category_path(category, model_type: current_klass), title: "view full details") %>
<% end %>
diff --git a/app/views/admin/categories/new.html.erb b/app/views/admin/categories/new.html.erb
index 2399a59282..66eb1204db 100644
--- a/app/views/admin/categories/new.html.erb
+++ b/app/views/admin/categories/new.html.erb
@@ -5,12 +5,12 @@
diff --git a/app/views/admin_general/_admin_navbar.html.erb b/app/views/admin_general/_admin_navbar.html.erb
index 8838e892bd..f63c41dbe1 100644
--- a/app/views/admin_general/_admin_navbar.html.erb
+++ b/app/views/admin_general/_admin_navbar.html.erb
@@ -26,7 +26,7 @@
Authorities
@@ -36,6 +36,7 @@
diff --git a/app/views/alaveteli_pro/batch_request_authority_searches/_browse.html.erb b/app/views/alaveteli_pro/batch_request_authority_searches/_browse.html.erb
index 219dfe144f..fe7af56893 100644
--- a/app/views/alaveteli_pro/batch_request_authority_searches/_browse.html.erb
+++ b/app/views/alaveteli_pro/batch_request_authority_searches/_browse.html.erb
@@ -3,7 +3,7 @@
<% else %>
<% show_add_all = feature_enabled?(:pro_batch_category_add_all, current_user) %>
- <% Category.public_body_root.tree.each do |heading| %>
+ <% PublicBody.categories.each do |heading| %>
-
diff --git a/app/views/public_body/list.html.erb b/app/views/public_body/list.html.erb
index b62ddf179b..111c0a2e05 100644
--- a/app/views/public_body/list.html.erb
+++ b/app/views/public_body/list.html.erb
@@ -31,7 +31,7 @@
- <% Category.public_body_root.tree.each do |heading| %>
+ <% PublicBody.categories.each do |heading| %>
<%= heading.title %>
<% heading.children.each do |category| %>
diff --git a/doc/CHANGES.md b/doc/CHANGES.md
index f834cc6dbc..2f6630fc9d 100644
--- a/doc/CHANGES.md
+++ b/doc/CHANGES.md
@@ -2,6 +2,7 @@
## Highlighted Features
+* Allow `InfoRequest` to be categorised (Graeme Porteous)
* Replace public body categories with generalised categories (Graeme Porteous)
* Add admin links to and from batch request show action (Graeme Porteous)
* Update request base calculated status for internal reviews (Graeme Porteous)
diff --git a/lib/tasks/temp.rake b/lib/tasks/temp.rake
index c351200613..fc2504b067 100644
--- a/lib/tasks/temp.rake
+++ b/lib/tasks/temp.rake
@@ -1,12 +1,12 @@
namespace :temp do
desc 'Migrate PublicBodyCategory into Category model'
task migrate_public_body_categories: :environment do
- next if Category.public_body_root.children.any?
+ next if PublicBody.categories.any?
scope = PublicBodyCategoryLink.by_display_order.to_a
count = scope.count
- root = Category.public_body_root
+ root = PublicBody.category_root
scope.each.with_index do |link, index|
h = link.public_body_heading
diff --git a/spec/controllers/admin/categories_controller_spec.rb b/spec/controllers/admin/categories_controller_spec.rb
index 964edcf673..78b9a1f9b4 100644
--- a/spec/controllers/admin/categories_controller_spec.rb
+++ b/spec/controllers/admin/categories_controller_spec.rb
@@ -7,9 +7,18 @@
expect(response).to be_successful
end
- it 'assigns root' do
- get :index
- expect(assigns(:root)).to eq(Category.public_body_root)
+ it 'raise 404 for unknown types' do
+ expect { get :index, params: { model_type: 'unknown' } }.to(
+ raise_error ApplicationController::RouteNotFound
+ )
+ end
+
+ it 'assigns root for correct model' do
+ get :index, params: { model_type: 'PublicBody' }
+ expect(assigns(:root)).to eq(PublicBody.category_root)
+
+ get :index, params: { model_type: 'InfoRequest' }
+ expect(assigns(:root)).to eq(InfoRequest.category_root)
end
it 'renders the index template' do
@@ -19,9 +28,12 @@
end
describe 'GET new' do
- it 'assigns root' do
- get :new
- expect(assigns(:root)).to eq(Category.public_body_root)
+ it 'assigns root for correct model' do
+ get :new, params: { model_type: 'PublicBody' }
+ expect(assigns(:root)).to eq(PublicBody.category_root)
+
+ get :new, params: { model_type: 'InfoRequest' }
+ expect(assigns(:root)).to eq(InfoRequest.category_root)
end
it 'responds successfully' do
@@ -47,15 +59,24 @@
end
describe 'POST create' do
- it 'assigns root' do
- post :create, params: { category: { title: 'Title' } }
- expect(assigns(:root)).to eq(Category.public_body_root)
+ it 'assigns root for correct model' do
+ post :create, params: {
+ model_type: 'PublicBody',
+ category: { title: 'Title' }
+ }
+ expect(assigns(:root)).to eq(PublicBody.category_root)
+
+ post :create, params: {
+ model_type: 'InfoRequest',
+ category: { title: 'Title' }
+ }
+ expect(assigns(:root)).to eq(InfoRequest.category_root)
end
it "default category's parent associations to root" do
post :create, params: { category: { title: 'Title' } }
expect(assigns(:category).parents).
- to match_array(Category.public_body_root)
+ to match_array(PublicBody.category_root)
end
it "saves new category's parent associations" do
@@ -93,7 +114,8 @@
it 'redirects to the categories index' do
post :create, params: { category: params }
- expect(response).to redirect_to(admin_categories_path)
+ expect(response).
+ to redirect_to(admin_categories_path(model_type: 'PublicBody'))
end
end
@@ -175,9 +197,12 @@
)
end
- it 'assigns root' do
- get :edit, params: { id: category.id }
- expect(assigns(:root)).to eq(Category.public_body_root)
+ it 'assigns root for correct model' do
+ get :edit, params: { model_type: 'PublicBody', id: category.id }
+ expect(assigns(:root)).to eq(PublicBody.category_root)
+
+ get :edit, params: { model_type: 'InfoRequest', id: category.id }
+ expect(assigns(:root)).to eq(InfoRequest.category_root)
end
it 'responds successfully' do
@@ -230,9 +255,20 @@
}
end
- it 'assigns root' do
- patch :update, params: { id: category.id, category: params }
- expect(assigns(:root)).to eq(Category.public_body_root)
+ it 'assigns root for correct model' do
+ patch :update, params: {
+ model_type: 'PublicBody',
+ id: category.id,
+ category: params
+ }
+ expect(assigns(:root)).to eq(PublicBody.category_root)
+
+ patch :update, params: {
+ model_type: 'InfoRequest',
+ id: category.id,
+ category: params
+ }
+ expect(assigns(:root)).to eq(InfoRequest.category_root)
end
it 'finds the category to update' do
@@ -243,7 +279,7 @@
it "default category's parent associations to root" do
patch :update, params: { id: category.id, category: params }
expect(assigns(:category).parents).
- to match_array(Category.public_body_root)
+ to match_array(PublicBody.category_root)
end
it "saves edits to a category's parent associations" do
@@ -302,7 +338,8 @@
it 'redirects to the category edit page' do
patch :update, params: { id: category.id, category: params }
- expect(response).to redirect_to(admin_categories_path)
+ expect(response).
+ to redirect_to(admin_categories_path(model_type: 'PublicBody'))
end
it 'saves edits to category_tag if the category has no associated bodies' do
@@ -405,7 +442,8 @@
it 'redirects to the edit page after a successful update' do
patch :update, params: { id: category.id, category: { title: 'Title' } }
- expect(response).to redirect_to(admin_categories_path)
+ expect(response).
+ to redirect_to(admin_categories_path(model_type: 'PublicBody'))
end
end
@@ -483,7 +521,8 @@
it 'redirects to the categories index' do
delete :destroy, params: { id: category.id }
- expect(response).to redirect_to(admin_categories_path)
+ expect(response).
+ to redirect_to(admin_categories_path(model_type: 'PublicBody'))
end
end
diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb
index 1f6a01b123..fd98830afe 100644
--- a/spec/models/category_spec.rb
+++ b/spec/models/category_spec.rb
@@ -93,7 +93,8 @@
describe '.roots scope' do
subject { described_class.roots }
- it { is_expected.to include(described_class.public_body_root) }
+ it { is_expected.to include(PublicBody.category_root) }
+ it { is_expected.to include(InfoRequest.category_root) }
end
describe '.with_parent scope' do
@@ -114,12 +115,6 @@
it { is_expected.to_not include(other_child) }
end
- describe '.public_body_root' do
- subject(:root) { described_class.public_body_root }
- it { is_expected.to be_a(described_class) }
- it { expect(root.title).to eq('PublicBody') }
- end
-
describe '#tree' do
subject { root.tree }
diff --git a/spec/models/concerns/categorisable.rb b/spec/models/concerns/categorisable.rb
new file mode 100644
index 0000000000..e634630764
--- /dev/null
+++ b/spec/models/concerns/categorisable.rb
@@ -0,0 +1,16 @@
+RSpec.shared_examples 'concerns/categorisable' do |factory_opts|
+ let(:record) { FactoryBot.create(*factory_opts) }
+
+ describe '.category_root' do
+ subject(:root) { described_class.category_root }
+ it { is_expected.to be_a(Category) }
+ it { expect(root.title).to eq(described_class.to_s) }
+ end
+
+ describe '.categories' do
+ it 'calls category_root.tree' do
+ expect(described_class).to receive_message_chain(:category_root, :tree)
+ described_class.categories
+ end
+ end
+end
diff --git a/spec/models/info_request_spec.rb b/spec/models/info_request_spec.rb
index c1001ea408..64e010bfd3 100644
--- a/spec/models/info_request_spec.rb
+++ b/spec/models/info_request_spec.rb
@@ -37,6 +37,7 @@
#
require 'spec_helper'
+require 'models/concerns/categorisable'
require 'models/concerns/info_request/title_validation'
require 'models/concerns/notable'
require 'models/concerns/notable_and_taggable'
@@ -44,6 +45,7 @@
require 'models/info_request/batch_pagination'
RSpec.describe InfoRequest do
+ it_behaves_like 'concerns/categorisable', :info_request
it_behaves_like 'concerns/info_request/title_validation', :info_request
it_behaves_like 'concerns/notable', :info_request
it_behaves_like 'concerns/notable_and_taggable', :info_request
diff --git a/spec/models/public_body_spec.rb b/spec/models/public_body_spec.rb
index 1ad829c811..db0a1f8788 100644
--- a/spec/models/public_body_spec.rb
+++ b/spec/models/public_body_spec.rb
@@ -27,11 +27,13 @@
#
require 'spec_helper'
+require 'models/concerns/categorisable'
require 'models/concerns/notable'
require 'models/concerns/notable_and_taggable'
require 'models/concerns/taggable'
RSpec.describe PublicBody do
+ it_behaves_like 'concerns/categorisable', :public_body
it_behaves_like 'concerns/notable', :public_body
it_behaves_like 'concerns/notable_and_taggable', :public_body
it_behaves_like 'concerns/taggable', :public_body