From 39a0d33bee988cb94f900d575de84aa1baf0752a Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Wed, 5 Jul 2023 21:51:36 -0700 Subject: [PATCH] July 2023 Feature Release: Tagging objects (#118) * Remove ap call * Fix remix render method * Downcase username on db end There was a bug where users with capital letters in their name could not access their profiles after we tried to make things case insensitive. * Remove ap call and unused code * Add granblue.team to cors This works now! * Implement all-entity search to support tagging objects (#117) * Add table for multisearch * Add new route for searching all entities * Make models multisearchable We're going to start with Character, Summon, Weapon and Jobs * Add method to Search controller This will search with trigram first, and then if there aren't enough results, search with prefixed text search * Add support for Japanese all-entity search --- app/blueprints/api/v1/search_blueprint.rb | 10 +++++ app/controllers/api/v1/search_controller.rb | 43 +++++++++++++++++++ app/models/character.rb | 10 +++++ app/models/job.rb | 12 ++++++ app/models/summon.rb | 10 +++++ app/models/weapon.rb | 10 +++++ config/routes.rb | 1 + ...230705065015_create_pg_search_documents.rb | 21 +++++++++ db/schema.rb | 15 ++++++- 9 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 app/blueprints/api/v1/search_blueprint.rb create mode 100644 db/migrate/20230705065015_create_pg_search_documents.rb diff --git a/app/blueprints/api/v1/search_blueprint.rb b/app/blueprints/api/v1/search_blueprint.rb new file mode 100644 index 0000000..f80531b --- /dev/null +++ b/app/blueprints/api/v1/search_blueprint.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Api + module V1 + class SearchBlueprint < Blueprinter::Base + identifier :searchable_id + fields :searchable_type, :granblue_id, :name_en, :name_jp, :element + end + end +end diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb index b60c3d0..842863b 100644 --- a/app/controllers/api/v1/search_controller.rb +++ b/app/controllers/api/v1/search_controller.rb @@ -3,6 +3,49 @@ module Api module V1 class SearchController < Api::V1::ApiController + TRIGRAM = { + trigram: { + threshold: 0.3 + } + }.freeze + + TSEARCH_WITH_PREFIX = { + tsearch: { + prefix: true, + dictionary: 'simple' + } + }.freeze + + def all + locale = search_params[:locale] || 'en' + + case locale + when 'en' + results = search_all_en + when 'ja' + results = search_all_ja + end + + render json: SearchBlueprint.render(results, root: :results) + end + + def search_all_en + PgSearch.multisearch_options = { using: TRIGRAM } + results = PgSearch.multisearch(search_params[:query]).limit(10) + + if (results.length < 5) && (search_params[:query].length >= 2) + PgSearch.multisearch_options = { using: TSEARCH_WITH_PREFIX } + results = PgSearch.multisearch(search_params[:query]).limit(10) + end + + results + end + + def search_all_ja + PgSearch.multisearch_options = { using: TSEARCH_WITH_PREFIX } + PgSearch.multisearch(search_params[:query]).limit(10) + end + def characters filters = search_params[:filters] locale = search_params[:locale] || 'en' diff --git a/app/models/character.rb b/app/models/character.rb index 6bb30a6..b89d3a1 100644 --- a/app/models/character.rb +++ b/app/models/character.rb @@ -3,6 +3,16 @@ class Character < ApplicationRecord include PgSearch::Model + multisearchable against: %i[name_en name_jp], + additional_attributes: lambda { |character| + { + name_en: character.name_en, + name_jp: character.name_jp, + granblue_id: character.granblue_id, + element: character.element + } + } + pg_search_scope :en_search, against: :name_en, using: { diff --git a/app/models/job.rb b/app/models/job.rb index 7cb8d6b..52ce307 100644 --- a/app/models/job.rb +++ b/app/models/job.rb @@ -1,9 +1,21 @@ # frozen_string_literal: true class Job < ApplicationRecord + include PgSearch::Model + belongs_to :party has_many :skills, class_name: 'JobSkill' + multisearchable against: %i[name_en name_jp], + additional_attributes: lambda { |job| + { + name_en: job.name_en, + name_jp: job.name_jp, + granblue_id: job.granblue_id, + element: 0 + } + } + belongs_to :base_job, foreign_key: 'base_job_id', class_name: 'Job', diff --git a/app/models/summon.rb b/app/models/summon.rb index cd9245a..59ce773 100644 --- a/app/models/summon.rb +++ b/app/models/summon.rb @@ -3,6 +3,16 @@ class Summon < ApplicationRecord include PgSearch::Model + multisearchable against: %i[name_en name_jp], + additional_attributes: lambda { |summon| + { + name_en: summon.name_en, + name_jp: summon.name_jp, + granblue_id: summon.granblue_id, + element: summon.element + } + } + pg_search_scope :en_search, against: :name_en, using: { diff --git a/app/models/weapon.rb b/app/models/weapon.rb index 9aedca3..fde26d2 100644 --- a/app/models/weapon.rb +++ b/app/models/weapon.rb @@ -3,6 +3,16 @@ class Weapon < ApplicationRecord include PgSearch::Model + multisearchable against: %i[name_en name_jp], + additional_attributes: lambda { |weapon| + { + name_en: weapon.name_en, + name_jp: weapon.name_jp, + granblue_id: weapon.granblue_id, + element: weapon.element + } + } + pg_search_scope :en_search, against: :name_en, using: { diff --git a/config/routes.rb b/config/routes.rb index 5864e34..9e13ee8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,6 +31,7 @@ Rails.application.routes.draw do post 'check/email', to: 'users#check_email' post 'check/username', to: 'users#check_username' + post 'search', to: 'search#all' post 'search/characters', to: 'search#characters' post 'search/weapons', to: 'search#weapons' post 'search/summons', to: 'search#summons' diff --git a/db/migrate/20230705065015_create_pg_search_documents.rb b/db/migrate/20230705065015_create_pg_search_documents.rb new file mode 100644 index 0000000..ce81c4f --- /dev/null +++ b/db/migrate/20230705065015_create_pg_search_documents.rb @@ -0,0 +1,21 @@ +class CreatePgSearchDocuments < ActiveRecord::Migration[7.0] + def up + say_with_time('Creating table for pg_search multisearch') do + create_table :pg_search_documents do |t| + t.text :content + t.string :granblue_id + t.string :name_en + t.string :name_jp + t.integer :element + t.belongs_to :searchable, type: :uuid, polymorphic: true, index: true + t.timestamps null: false + end + end + end + + def down + say_with_time('Dropping table for pg_search multisearch') do + drop_table :pg_search_documents + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 0dd39f7..6abca66 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_07_02_035508) do +ActiveRecord::Schema[7.0].define(version: 2023_07_05_065015) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gin" enable_extension "pg_trgm" @@ -361,6 +361,19 @@ ActiveRecord::Schema[7.0].define(version: 2023_07_02_035508) do t.index ["user_id"], name: "index_parties_on_user_id" end + create_table "pg_search_documents", force: :cascade do |t| + t.text "content" + t.string "granblue_id" + t.string "name_en" + t.string "name_jp" + t.integer "element" + t.string "searchable_type" + t.uuid "searchable_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["searchable_type", "searchable_id"], name: "index_pg_search_documents_on_searchable" + end + create_table "raid_groups", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "name_en", null: false t.string "name_jp", null: false