From 3a407161b4ad9ba1e7e67af4509230ed4d573bc4 Mon Sep 17 00:00:00 2001 From: Ryan Kendall Date: Fri, 15 Sep 2023 15:54:05 +0100 Subject: [PATCH] refactor: removed boilerplate from filterables --- app/models/concerns/filter_form.rb | 58 ++++++++++++++ app/models/frameworks/framework/filtering.rb | 75 +++---------------- app/models/frameworks/provider/filtering.rb | 31 +------- .../frameworks/provider_contact/filtering.rb | 38 +--------- .../frameworks/_index_filters.html.erb | 4 +- .../provider_contacts/_index_filters.html.erb | 2 +- 6 files changed, 78 insertions(+), 130 deletions(-) create mode 100644 app/models/concerns/filter_form.rb diff --git a/app/models/concerns/filter_form.rb b/app/models/concerns/filter_form.rb new file mode 100644 index 000000000..03ed2db05 --- /dev/null +++ b/app/models/concerns/filter_form.rb @@ -0,0 +1,58 @@ +module FilterForm + extend ActiveSupport::Concern + + included do + include ActiveModel::Model + include ActiveModel::Validations + include ActiveModel::Attributes + + attribute :sort_by + attribute :sort_order + end + + def results + records = scoped_records + filters.each { |filter| records = filter.filter(records) } + records.sorted_by(sort_by:, sort_order:) + end + + def number_of_selected(field) + send(field.to_s.singularize).count(&:present?) + end + +private + + def filters + self.class.filter_attibutes.map do |attr, options| + Support::Concerns::ScopeFilter.new(send(attr), **options) + end + end + + class_methods do + def initial_scope(proc) + define_method :scoped_records do + proc.call + end + end + + def sort_options(proc) + define_method :available_sort_options do + proc.call + end + end + + def filter_by(name, default: -> { [] }, multiple: true, options: -> { [] }, scope: nil) + attribute(name, default:) + + filter_attibutes[name] = { scope: scope.presence || "by_#{name}", multiple: } + + define_method "available_#{name}_options" do + options.call + end + end + + def filter_attibutes + @filter_attibutes ||= {} + end + end +end diff --git a/app/models/frameworks/framework/filtering.rb b/app/models/frameworks/framework/filtering.rb index e90906ccb..67a3e2680 100644 --- a/app/models/frameworks/framework/filtering.rb +++ b/app/models/frameworks/framework/filtering.rb @@ -1,70 +1,15 @@ class Frameworks::Framework::Filtering - include ActiveModel::Model - include ActiveModel::Attributes - include ActiveModel::Validations + include FilterForm - attribute :scoped_frameworks, default: -> { Frameworks::Framework } - attribute :status, default: -> { [] } - attribute :provider, default: -> { [] } - attribute :e_and_o_lead, default: -> { [] } - attribute :proc_ops_lead, default: -> { [] } - attribute :category, default: -> { [] } - attribute :provider_contact, default: -> { [] } - attribute :sort_by - attribute :sort_order + get_agents = ->(type_id) { Support::Agent.by_first_name.where(id: Frameworks::Framework.pluck(type_id)) } - def results - frameworks = scoped_frameworks + initial_scope -> { Frameworks::Framework } + sort_options -> { Frameworks::Framework.available_sort_options } - filters.each { |filter| frameworks = filter.filter(frameworks) } - - frameworks.sorted_by(sort_by:, sort_order:) - end - - def available_category_options - Support::Category.order("title ASC").where(id: Frameworks::FrameworkCategory.pluck(:support_category_id)).pluck(:title, :id) - end - - def available_provider_filter_options - Frameworks::Provider.order("short_name ASC").pluck(:short_name, :id) - end - - def available_e_and_o_lead_options - Support::Agent.by_first_name.where(id: Frameworks::Framework.pluck(:e_and_o_lead_id)) - .map { |agent| [agent.full_name, agent.id] } - end - - def available_proc_ops_lead_options - Support::Agent.by_first_name.where(id: Frameworks::Framework.pluck(:proc_ops_lead_id)) - .map { |agent| [agent.full_name, agent.id] } - end - - def available_status_filter_options - Frameworks::Framework.statuses.map { |label, _id| [label.humanize, label] } - end - - def available_provider_contact_options - Frameworks::ProviderContact.sort_by_name("ascending").pluck(:name, :id) - end - - def available_sort_options - Frameworks::Framework.available_sort_options - end - - def number_of_selected(field) - send(field.to_s.singularize).count(&:present?) - end - -private - - def filters - [ - Support::Concerns::ScopeFilter.new(status, scope: :by_status), - Support::Concerns::ScopeFilter.new(provider, scope: :by_provider), - Support::Concerns::ScopeFilter.new(e_and_o_lead, scope: :by_e_and_o_lead), - Support::Concerns::ScopeFilter.new(proc_ops_lead, scope: :by_proc_ops_lead), - Support::Concerns::ScopeFilter.new(category, scope: :by_category), - Support::Concerns::ScopeFilter.new(provider_contact, scope: :by_provider_contact), - ] - end + filter_by :status, options: -> { Frameworks::Framework.statuses.map { |label, _id| [label.humanize, label] } } + filter_by :provider, options: -> { Frameworks::Provider.order("short_name ASC").pluck(:short_name, :id) } + filter_by :e_and_o_lead, options: -> { get_agents[:e_and_o_lead_id].map { |agent| [agent.full_name, agent.id] } } + filter_by :proc_ops_lead, options: -> { get_agents[:proc_ops_lead_id].map { |agent| [agent.full_name, agent.id] } } + filter_by :category, options: -> { Support::Category.order("title ASC").where(id: Frameworks::FrameworkCategory.pluck(:support_category_id)).pluck(:title, :id) } + filter_by :provider_contact, options: -> { Frameworks::ProviderContact.sort_by_name("ascending").pluck(:name, :id) } end diff --git a/app/models/frameworks/provider/filtering.rb b/app/models/frameworks/provider/filtering.rb index eb29c1627..1f663ff5b 100644 --- a/app/models/frameworks/provider/filtering.rb +++ b/app/models/frameworks/provider/filtering.rb @@ -1,31 +1,6 @@ class Frameworks::Provider::Filtering - include ActiveModel::Model - include ActiveModel::Attributes - include ActiveModel::Validations + include FilterForm - attribute :scoped_providers, default: -> { Frameworks::Provider } - attribute :sort_by - attribute :sort_order - - def results - providers = scoped_providers - - filters.each { |filter| providers = filter.filter(providers) } - - providers.sorted_by(sort_by:, sort_order:) - end - - def available_sort_options - Frameworks::Provider.available_sort_options - end - - def number_of_selected(field) - send(field.to_s.singularize).count(&:present?) - end - -private - - def filters - [] - end + initial_scope -> { Frameworks::Provider } + sort_options -> { Frameworks::Provider.available_sort_options } end diff --git a/app/models/frameworks/provider_contact/filtering.rb b/app/models/frameworks/provider_contact/filtering.rb index 7e862aa09..102e2186d 100644 --- a/app/models/frameworks/provider_contact/filtering.rb +++ b/app/models/frameworks/provider_contact/filtering.rb @@ -1,38 +1,8 @@ class Frameworks::ProviderContact::Filtering - include ActiveModel::Model - include ActiveModel::Attributes - include ActiveModel::Validations + include FilterForm - attribute :scoped_provider_contacts, default: -> { Frameworks::ProviderContact } - attribute :provider, default: -> { [] } - attribute :sort_by - attribute :sort_order + initial_scope -> { Frameworks::ProviderContact } + sort_options -> { Frameworks::ProviderContact.available_sort_options } - def results - provider_contacts = scoped_provider_contacts - - filters.each { |filter| provider_contacts = filter.filter(provider_contacts) } - - provider_contacts.sorted_by(sort_by:, sort_order:) - end - - def available_sort_options - Frameworks::ProviderContact.available_sort_options - end - - def available_provider_filter_options - Frameworks::Provider.order("short_name ASC").pluck(:short_name, :id) - end - - def number_of_selected(field) - send(field.to_s.singularize).count(&:present?) - end - -private - - def filters - [ - Support::Concerns::ScopeFilter.new(provider, scope: :by_provider), - ] - end + filter_by :provider, options: -> { Frameworks::Provider.order("short_name ASC").pluck(:short_name, :id) } end diff --git a/app/views/frameworks/frameworks/_index_filters.html.erb b/app/views/frameworks/frameworks/_index_filters.html.erb index ed6f04594..c281ac1e7 100644 --- a/app/views/frameworks/frameworks/_index_filters.html.erb +++ b/app/views/frameworks/frameworks/_index_filters.html.erb @@ -19,7 +19,7 @@ <%= expander title: "Status", subtitle: "#{@filtering.number_of_selected(:statuses)} selected", expanded: true do %> <%= form.govuk_check_boxes_fieldset :status, legend: nil, small: true, form_group: { class: "govuk-!-margin-bottom-0" } do %> - <% @filtering.available_status_filter_options.each do |status| %> + <% @filtering.available_status_options.each do |status| %> <%= form.govuk_check_box :status, status.last, exclusive: false, label: { text: status.first } %> <% end %> <% end %> @@ -35,7 +35,7 @@ <%= expander title: "Provider", subtitle: "#{@filtering.number_of_selected(:providers)} selected", expanded: @filtering.number_of_selected(:providers).positive? do %> <%= form.govuk_check_boxes_fieldset :provider, legend: nil, small: true, form_group: { class: "govuk-!-margin-bottom-0" } do %> - <% @filtering.available_provider_filter_options.each do |option| %> + <% @filtering.available_provider_options.each do |option| %> <%= form.govuk_check_box :provider, option.last, exclusive: false, label: { text: option.first } %> <% end %> <% end %> diff --git a/app/views/frameworks/provider_contacts/_index_filters.html.erb b/app/views/frameworks/provider_contacts/_index_filters.html.erb index 80f78033f..1967ed99f 100644 --- a/app/views/frameworks/provider_contacts/_index_filters.html.erb +++ b/app/views/frameworks/provider_contacts/_index_filters.html.erb @@ -19,7 +19,7 @@ <%= expander title: "Provider", subtitle: "#{@filtering.number_of_selected(:providers)} selected", expanded: true do %> <%= form.govuk_check_boxes_fieldset :provider, legend: nil, small: true, form_group: { class: "govuk-!-margin-bottom-0" } do %> - <% @filtering.available_provider_filter_options.each do |option| %> + <% @filtering.available_provider_options.each do |option| %> <%= form.govuk_check_box :provider, option.last, exclusive: false, label: { text: option.first } %> <% end %> <% end %>