From 1a6cd356bffb10ea15d8e4dc2ffddcbbf834b2d8 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 22 Jun 2020 16:28:05 +0200 Subject: [PATCH] WIP: using postgres for full-text search in projects --- CHANGELOG.md | 1 + app/controllers/api/projects_controller.rb | 7 +++--- app/models/project.rb | 10 +++++--- app/views/api/projects/index.json.jbuilder | 2 +- config/environments/development.rb | 5 +++- ..._pg_search_dmetaphone_support_functions.rb | 24 ++++++++++++++++++ db/schema.rb | 25 ++++++++++--------- doc/postgresql_readme.md | 1 + env.example | 4 +-- 9 files changed, 56 insertions(+), 23 deletions(-) create mode 100644 db/migrate/20200622135401_add_pg_search_dmetaphone_support_functions.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 61067c59d..fab0b83a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Updated CarrierWave to 2.1.0 - Updated redis to v6, with alpine image - Updated Sidekiq to 6.0.7 +- Updated documentation - Fix a bug: managers do not see the name of the user who reserved a slot - Fix a bug: OpenAPI documentation is not available - Fix a bug: summary of create training availability shows incorrect alert about slot splitting diff --git a/app/controllers/api/projects_controller.rb b/app/controllers/api/projects_controller.rb index b83f44154..83658f415 100644 --- a/app/controllers/api/projects_controller.rb +++ b/app/controllers/api/projects_controller.rb @@ -53,10 +53,9 @@ class API::ProjectsController < API::ApiController end def search - query_params = JSON.parse(params[:search]) - records = Project.search(query_params, current_user).page(params[:page]).records - @total = records.total - @projects = records.includes(:users, :project_image) + records = Project.published.drafts(current_user.statistic_profile.id).search(params[:q]) + @total = records.count + @projects = records.includes(:users, :project_image).page(params[:page]).per(20) render :index end diff --git a/app/models/project.rb b/app/models/project.rb index f468bdf4a..482f02dc5 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -51,6 +51,7 @@ class Project < ApplicationRecord # scopes scope :published, -> { where("state = 'published'") } + scope :drafts, ->(author_profile) { where("state = 'draft' AND author_statistic_profile_id = ?", author_profile) } pg_search_scope :search, against: { name: 'A', @@ -60,12 +61,15 @@ class Project < ApplicationRecord associated_against: { project_steps: { title: 'D', - description: 'E' + description: 'D' } }, using: { - tsearch: { dictionary: Rails.application.secrets.postgresql_language_analyzer } - } + tsearch: { dictionary: Rails.application.secrets.postgresql_language_analyzer }, + trigram: {}, + dmetaphone: {} + }, + ignoring: :accents private diff --git a/app/views/api/projects/index.json.jbuilder b/app/views/api/projects/index.json.jbuilder index 6f787dfcc..15b4e3f5c 100644 --- a/app/views/api/projects/index.json.jbuilder +++ b/app/views/api/projects/index.json.jbuilder @@ -3,7 +3,7 @@ json.projects @projects do |project| json.extract! project, :id, :name, :description, :licence_id, :slug, :state json.author_id project.author.user_id - + json.project_image project.project_image.attachment.medium.url if project.project_image json.user_ids project.user_ids end diff --git a/config/environments/development.rb b/config/environments/development.rb index 54f35bf93..d6a7aa875 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -43,7 +43,10 @@ Rails.application.configure do config.action_mailer.perform_caching = false config.action_mailer.delivery_method = :smtp - config.action_mailer.smtp_settings = { address: 'fabmanager-mailcatcher', port: 1025 } + config.action_mailer.smtp_settings = { + address: Rails.application.secrets.smtp_address, + port: Rails.application.secrets.smtp_port + } config.action_mailer.raise_delivery_errors = false config.action_mailer.default_url_options = { host: Rails.application.secrets.default_host, diff --git a/db/migrate/20200622135401_add_pg_search_dmetaphone_support_functions.rb b/db/migrate/20200622135401_add_pg_search_dmetaphone_support_functions.rb new file mode 100644 index 000000000..7d460c1c7 --- /dev/null +++ b/db/migrate/20200622135401_add_pg_search_dmetaphone_support_functions.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# Create a PostgreSQL specific function to make pg_search gem working with fuzzystrmatch +class AddPgSearchDmetaphoneSupportFunctions < ActiveRecord::Migration[5.2] + def self.up + say_with_time('Adding support functions for pg_search :dmetaphone') do + execute 'CREATE EXTENSION IF NOT EXISTS fuzzystrmatch;' + execute <<~'SQL' + CREATE OR REPLACE FUNCTION pg_search_dmetaphone(text) RETURNS text LANGUAGE SQL IMMUTABLE STRICT AS $function$ + SELECT array_to_string(ARRAY(SELECT dmetaphone(unnest(regexp_split_to_array($1, E'\\s+')))), ' ') + $function$; + SQL + end + end + + def self.down + say_with_time('Dropping support functions for pg_search :dmetaphone') do + execute <<~'SQL' + DROP FUNCTION pg_search_dmetaphone(text); + SQL + execute 'DROP EXTENSION IF EXISTS fuzzystrmatch;' + end + end +end diff --git a/db/schema.rb b/db/schema.rb index fd65d29b9..b05131656 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,16 +10,17 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_05_11_075933) do +ActiveRecord::Schema.define(version: 2020_06_22_135401) do # These are extensions that must be enabled in order to support this database + enable_extension "fuzzystrmatch" enable_extension "pg_trgm" enable_extension "plpgsql" enable_extension "unaccent" create_table "abuses", id: :serial, force: :cascade do |t| - t.string "signaled_type" t.integer "signaled_id" + t.string "signaled_type" t.string "first_name" t.string "last_name" t.string "email" @@ -48,8 +49,8 @@ ActiveRecord::Schema.define(version: 2020_05_11_075933) do t.string "locality" t.string "country" t.string "postal_code" - t.string "placeable_type" t.integer "placeable_id" + t.string "placeable_type" t.datetime "created_at" t.datetime "updated_at" end @@ -63,8 +64,8 @@ ActiveRecord::Schema.define(version: 2020_05_11_075933) do end create_table "assets", id: :serial, force: :cascade do |t| - t.string "viewable_type" t.integer "viewable_id" + t.string "viewable_type" t.string "attachment" t.string "type" t.datetime "created_at" @@ -132,8 +133,8 @@ ActiveRecord::Schema.define(version: 2020_05_11_075933) do end create_table "credits", id: :serial, force: :cascade do |t| - t.string "creditable_type" t.integer "creditable_id" + t.string "creditable_type" t.integer "plan_id" t.integer "hours" t.datetime "created_at" @@ -285,8 +286,8 @@ ActiveRecord::Schema.define(version: 2020_05_11_075933) do end create_table "invoices", id: :serial, force: :cascade do |t| - t.string "invoiced_type" t.integer "invoiced_id" + t.string "invoiced_type" t.string "stp_invoice_id" t.integer "total" t.datetime "created_at" @@ -349,15 +350,15 @@ ActiveRecord::Schema.define(version: 2020_05_11_075933) do create_table "notifications", id: :serial, force: :cascade do |t| t.integer "receiver_id" - t.string "attached_object_type" t.integer "attached_object_id" + t.string "attached_object_type" t.integer "notification_type_id" t.boolean "is_read", default: false t.datetime "created_at" t.datetime "updated_at" t.string "receiver_type" t.boolean "is_send", default: false - t.jsonb "meta_data", default: "{}" + t.jsonb "meta_data", default: {} t.index ["notification_type_id"], name: "index_notifications_on_notification_type_id" t.index ["receiver_id"], name: "index_notifications_on_receiver_id" end @@ -457,8 +458,8 @@ ActiveRecord::Schema.define(version: 2020_05_11_075933) do create_table "prices", id: :serial, force: :cascade do |t| t.integer "group_id" t.integer "plan_id" - t.string "priceable_type" t.integer "priceable_id" + t.string "priceable_type" t.integer "amount" t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -565,8 +566,8 @@ ActiveRecord::Schema.define(version: 2020_05_11_075933) do t.text "message" t.datetime "created_at" t.datetime "updated_at" - t.string "reservable_type" t.integer "reservable_id" + t.string "reservable_type" t.integer "nb_reserve_places" t.integer "statistic_profile_id" t.index ["reservable_type", "reservable_id"], name: "index_reservations_on_reservable_type_and_reservable_id" @@ -575,8 +576,8 @@ ActiveRecord::Schema.define(version: 2020_05_11_075933) do create_table "roles", id: :serial, force: :cascade do |t| t.string "name" - t.string "resource_type" t.integer "resource_id" + t.string "resource_type" t.datetime "created_at" t.datetime "updated_at" t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id" @@ -867,8 +868,8 @@ ActiveRecord::Schema.define(version: 2020_05_11_075933) do create_table "wallet_transactions", id: :serial, force: :cascade do |t| t.integer "wallet_id" - t.string "transactable_type" t.integer "transactable_id" + t.string "transactable_type" t.string "transaction_type" t.integer "amount" t.datetime "created_at", null: false diff --git a/doc/postgresql_readme.md b/doc/postgresql_readme.md index 788ba58af..9ec087b5f 100644 --- a/doc/postgresql_readme.md +++ b/doc/postgresql_readme.md @@ -75,3 +75,4 @@ This is currently not supported, because of some PostgreSQL specific instruction - `db/migrate/20190522115230_migrate_user_to_invoicing_profile.rb` is using `CREATE RULE` and `DROP RULE`; - `db/migrate/20200511075933_fix_accounting_periods.rb` is using `CREATE RULE` and `DROP RULE`; - `app/models/project.rb` is using the `pg_search` gem. + - `db/migrate/20200622135401_add_pg_search_dmetaphone_support_functions.rb` is using [fuzzystrmatch](http://www.postgresql.org/docs/current/static/fuzzystrmatch.html) module and defines a PL/pgSQL function (`pg_search_dmetaphone()`); diff --git a/env.example b/env.example index b0291ed74..aab7da016 100644 --- a/env.example +++ b/env.example @@ -14,8 +14,8 @@ DEFAULT_PROTOCOL=http # Email config DELIVERY_METHOD=smtp -SMTP_ADDRESS= -SMTP_PORT=587 +SMTP_ADDRESS=fabmanager-mailcatcher +SMTP_PORT=1025 SMTP_USER_NAME= SMTP_PASSWORD= SMTP_AUTHENTICATION=plain