From 805e290322771810dbbe92f575ad9cf91d1081c5 Mon Sep 17 00:00:00 2001 From: Brian Hayden Date: Wed, 25 Oct 2023 10:51:45 -0500 Subject: [PATCH] Elevate subgroup to first-class status Subcategory/subgroup needs to be a real entity, not lumped into keywords, for true filtering. --- app/controllers/api/studies_controller.rb | 7 +++- app/controllers/studies_controller.rb | 3 +- app/models/trial.rb | 38 ++++++++++++++++++- app/models/trial_subgroup.rb | 6 +++ app/views/studies/index.html.erb | 2 +- ...156_create_study_finder_trial_subgroups.rb | 10 +++++ db/schema.rb | 24 +++++++++++- spec/factories/trial_subgroups.rb | 6 +++ spec/models/trial_subgroup_spec.rb | 5 +++ 9 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 app/models/trial_subgroup.rb create mode 100644 db/migrate/20231024190156_create_study_finder_trial_subgroups.rb create mode 100644 spec/factories/trial_subgroups.rb create mode 100644 spec/models/trial_subgroup_spec.rb diff --git a/app/controllers/api/studies_controller.rb b/app/controllers/api/studies_controller.rb index 6c35fbc..f2bd965 100644 --- a/app/controllers/api/studies_controller.rb +++ b/app/controllers/api/studies_controller.rb @@ -1,6 +1,6 @@ class Api::StudiesController < ApiController def index - @trials = Trial.includes(:trial_keywords, :conditions, :trial_interventions, :locations).all + @trials = Trial.includes(:trial_keywords, :conditions, :subgroups, :trial_interventions, :locations).all end def visible @@ -9,7 +9,7 @@ def visible end def show - @trial = Trial.includes(:trial_keywords, :conditions, :trial_interventions, :locations).find_by(system_id: params[:id]) + @trial = Trial.includes(:trial_keywords, :conditions, :subgroups, :trial_interventions, :locations).find_by(system_id: params[:id]) end def update @@ -19,6 +19,7 @@ def update @trial.update_interventions!(params[:interventions].to_a) @trial.update_keywords!(params[:keywords]) @trial.update_conditions!(params[:conditions]) + @trial.update_subgroups!(params[:subgroups]) @trial.update_locations!(params[:locations]) @trial.update!(trial_params) end @@ -35,6 +36,7 @@ def create @trial.transaction do @trial.update_keywords!(params[:keywords]) @trial.update_conditions!(params[:conditions]) + @trial.update_subgroups!(params[:subgroups]) @trial.update_locations!(params[:locations]) @trial.update_interventions!(params[:interventions]) end @@ -93,6 +95,7 @@ def api_params :protocol_type, :recruiting, :simple_description, + :subgroups, :display_simple_description, :system_id, :verification_date, diff --git a/app/controllers/studies_controller.rb b/app/controllers/studies_controller.rb index 7a1cd03..62f2f12 100644 --- a/app/controllers/studies_controller.rb +++ b/app/controllers/studies_controller.rb @@ -8,6 +8,7 @@ def index @attribute_settings = SystemInfo.trial_attribute_settings @group = Group.where(id: search_hash[:category]).first + @subgroup = Subgroup.where(id: search_hash[:subcat]).first @trials = Trial.execute_search(search_hash).page(search_params[:page]).results @search_query = search_hash[:q].try(:downcase) || "" @@ -95,6 +96,6 @@ def email_me private def search_params - params.permit(:page, search: [:category, :q, :healthy_volunteers, :gender, :children, :adults]) + params.permit(:page, search: [:category, :subcat, :q, :healthy_volunteers, :gender, :children, :adults]) end end diff --git a/app/models/trial.rb b/app/models/trial.rb index 1357113..0771a55 100644 --- a/app/models/trial.rb +++ b/app/models/trial.rb @@ -23,6 +23,9 @@ class Trial < ApplicationRecord has_many :conditions, through: :trial_conditions has_many :condition_groups, through: :trial_conditions + has_many :trial_subgroups + has_many :subgroups, through: :trial_subgroups + has_many :trial_sites has_many :sites, through: :trial_sites @@ -114,6 +117,10 @@ def category_ids condition_groups.map { |e| e.group_id } end + def subcategory_ids + trial_subgroups.map { |e| e.subgroup_id } + end + def keyword_suggest { input: trial_keywords.where.not(keyword: nil).map { |k| k.keyword.try(:downcase) } @@ -140,6 +147,28 @@ def condition_values conditions.map(&:condition).sort end + def subgroup_values + subgroups.map(&:name).sort + end + + def update_subgroups!(subgroups) + return if subgroups.nil? + + existing_subgroups = subgroup_values + subgroups_to_add = subgroups - existing_subgroups + subgroups_to_delete = existing_subgroups - subgroups + + transaction(requires_new: true) do + trial_subgroups.includes(:subgroup).where(Subgroup.table_name => { name: subgroups_to_delete }).delete_all + + subgroups_to_add.each do |subgroup| + trial_subgroups.create(subgroup: Subgroup.find_or_initialize_by(name: subgroup, group_id: category_ids)) + end + end + + __elasticsearch__.update_document + end + def update_keywords!(keywords) return if keywords.nil? @@ -296,6 +325,7 @@ def update_interventions!(intervention_data) indexes :pi_id indexes :category_ids + indexes :subcategory_ids indexes :keyword_suggest, type: 'completion', analyzer: 'typeahead', search_analyzer: 'typeahead' @@ -405,7 +435,7 @@ def as_indexed_json(options={}) ] } }, - methods: [:display_title, :min_age, :max_age, :interventions, :conditions_map, :category_ids, :keywords, :keyword_suggest] + methods: [:display_title, :min_age, :max_age, :interventions, :conditions_map, :category_ids, :subcategory_ids, :keywords, :keyword_suggest] ) end @@ -538,7 +568,7 @@ def self.filters(search) ret = [] ret << { term: { visible: true } } ret << { term: { approved: true } } - if (search.has_key?('healthy_volunteers') and search[:healthy_volunteers] == "1") or search.has_key?('category') or search.has_key?('gender') + if (search.has_key?('healthy_volunteers') and search[:healthy_volunteers] == "1") or search.has_key?('category') or search.has_key?('subcat') or search.has_key?('gender') if search.has_key?('healthy_volunteers') and search[:healthy_volunteers] == "1" ret << { term: { healthy_volunteers: true } } end @@ -547,6 +577,10 @@ def self.filters(search) ret << { term: { category_ids: search[:category] } } end + if search.has_key?('subcat') + ret << { term: { subcategory_ids: search[:subcat] } } + end + if (search.has_key?('gender')) and (search[:gender] == 'Male' or search[:gender] == 'Female') ret << { terms: { gender: ['all', 'Both', search[:gender].try(:downcase)] }} end diff --git a/app/models/trial_subgroup.rb b/app/models/trial_subgroup.rb new file mode 100644 index 0000000..c7b2cd4 --- /dev/null +++ b/app/models/trial_subgroup.rb @@ -0,0 +1,6 @@ +class TrialSubgroup < ApplicationRecord + self.table_name = 'study_finder_trial_subgroups' + + belongs_to :subgroup + belongs_to :trial +end diff --git a/app/views/studies/index.html.erb b/app/views/studies/index.html.erb index bbf52cf..46c508f 100644 --- a/app/views/studies/index.html.erb +++ b/app/views/studies/index.html.erb @@ -32,7 +32,7 @@ <% url = request.original_url.encode('utf-8', 'ascii-8bit') %> <% p = request.query_parameters.dup %> <% @group.subgroups.sort_by{ |l| l.name }.each do |subgroup| %> - <% p[:search][:q] = subgroup.name.try(:downcase) %> + <% p[:search][:subcat] = subgroup.id %> <%= link_to subgroup.name, "studies?#{p.to_query}", class: 'btn btn-school btn-subgroup' %> <% end %> diff --git a/db/migrate/20231024190156_create_study_finder_trial_subgroups.rb b/db/migrate/20231024190156_create_study_finder_trial_subgroups.rb new file mode 100644 index 0000000..a476598 --- /dev/null +++ b/db/migrate/20231024190156_create_study_finder_trial_subgroups.rb @@ -0,0 +1,10 @@ +class CreateStudyFinderTrialSubgroups < ActiveRecord::Migration[7.0] + def change + create_table :study_finder_trial_subgroups do |t| + t.references :subgroup, null: false, foreign_key: {to_table: :study_finder_subgroups} + t.references :trial, null: false, foreign_key: {to_table: :study_finder_trials} + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 22dea6c..2d5c3d8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_08_07_164537) do +ActiveRecord::Schema[7.0].define(version: 2023_10_24_190156) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -227,6 +227,15 @@ t.datetime "updated_at", precision: nil, null: false end + create_table "study_finder_trial_subgroups", force: :cascade do |t| + t.bigint "subgroup_id", null: false + t.bigint "trial_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["subgroup_id"], name: "index_study_finder_trial_subgroups_on_subgroup_id" + t.index ["trial_id"], name: "index_study_finder_trial_subgroups_on_trial_id" + end + create_table "study_finder_trials", id: :serial, force: :cascade do |t| t.string "system_id" t.string "brief_title", limit: 1000 @@ -328,6 +337,19 @@ t.boolean "display_if_null_on_show", default: true end + create_table "trial_subgroups", force: :cascade do |t| + t.bigint "study_finder_subgroup_id", null: false + t.bigint "study_finder_trial_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["study_finder_subgroup_id"], name: "index_trial_subgroups_on_study_finder_subgroup_id" + t.index ["study_finder_trial_id"], name: "index_trial_subgroups_on_study_finder_trial_id" + end + add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" + add_foreign_key "study_finder_trial_subgroups", "study_finder_subgroups", column: "subgroup_id" + add_foreign_key "study_finder_trial_subgroups", "study_finder_trials", column: "trial_id" + add_foreign_key "trial_subgroups", "study_finder_subgroups" + add_foreign_key "trial_subgroups", "study_finder_trials" end diff --git a/spec/factories/trial_subgroups.rb b/spec/factories/trial_subgroups.rb new file mode 100644 index 0000000..bd3aab2 --- /dev/null +++ b/spec/factories/trial_subgroups.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :trial_subgroup do + subgroup { nil } + trial { nil } + end +end diff --git a/spec/models/trial_subgroup_spec.rb b/spec/models/trial_subgroup_spec.rb new file mode 100644 index 0000000..4615c63 --- /dev/null +++ b/spec/models/trial_subgroup_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe TrialSubgroup, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end