Get search dictionary based on I18n.default_locale (merge pull request #3856)
Implementation tries to be open for further extensions, such as deciding on search dictionary based on configuration option or by locale set for given user.
This commit is contained in:
committed by
GitHub
parent
426c1c5fd2
commit
d99875cde2
@@ -19,7 +19,8 @@ module SearchCache
|
|||||||
end
|
end
|
||||||
|
|
||||||
def set_tsvector(value, weight)
|
def set_tsvector(value, weight)
|
||||||
"setweight(to_tsvector('spanish', unaccent(coalesce(#{quote(strip_html(value))}, ''))), #{quote(weight)})"
|
dict = quote(SearchDictionarySelector.call)
|
||||||
|
"setweight(to_tsvector(#{dict}, unaccent(coalesce(#{quote(strip_html(value))}, ''))), #{quote(weight)})"
|
||||||
end
|
end
|
||||||
|
|
||||||
def quote(value)
|
def quote(value)
|
||||||
|
|||||||
@@ -5,14 +5,18 @@ module Searchable
|
|||||||
include PgSearch
|
include PgSearch
|
||||||
include SearchCache
|
include SearchCache
|
||||||
|
|
||||||
pg_search_scope :pg_search, {
|
pg_search_scope :pg_search, ->(query) do
|
||||||
against: :ignored, # not used since using a tsvector_column
|
cached_votes_up_present = column_names.include?("cached_votes_up")
|
||||||
using: {
|
{
|
||||||
tsearch: { tsvector_column: "tsv", dictionary: "spanish", prefix: true }
|
against: :ignored, # not used since using a tsvector_column
|
||||||
},
|
using: {
|
||||||
ignoring: :accents,
|
tsearch: { tsvector_column: "tsv", dictionary: SearchDictionarySelector.call, prefix: true }
|
||||||
ranked_by: "(:tsearch)",
|
},
|
||||||
order_within_rank: (column_names.include?("cached_votes_up") ? "#{table_name}.cached_votes_up DESC" : nil)
|
ignoring: :accents,
|
||||||
}
|
ranked_by: "(:tsearch)",
|
||||||
|
order_within_rank: (cached_votes_up_present ? "#{table_name}.cached_votes_up DESC" : nil),
|
||||||
|
query: query
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
42
lib/search_dictionary_selector.rb
Normal file
42
lib/search_dictionary_selector.rb
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
module SearchDictionarySelector
|
||||||
|
SQL_QUERY = "SELECT cfgname FROM pg_ts_config".freeze
|
||||||
|
I18N_TO_DICTIONARY = {
|
||||||
|
en: "english",
|
||||||
|
de: "german",
|
||||||
|
fi: "finnish",
|
||||||
|
fr: "french",
|
||||||
|
dk: "danish",
|
||||||
|
nl: "dutch",
|
||||||
|
hu: "hungarian",
|
||||||
|
it: "italian",
|
||||||
|
nn: "norwegian",
|
||||||
|
nb: "norwegian",
|
||||||
|
pt: "portuguese",
|
||||||
|
ro: "romanian",
|
||||||
|
ru: "russian",
|
||||||
|
es: "spanish",
|
||||||
|
sv: "swedish",
|
||||||
|
tr: "turkish"
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
class << self
|
||||||
|
def call
|
||||||
|
find_from_i18n_default
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def find_from_i18n_default
|
||||||
|
key_to_lookup = I18n.default_locale.to_s.split("-").first.to_sym
|
||||||
|
|
||||||
|
dictionary = I18N_TO_DICTIONARY[key_to_lookup]
|
||||||
|
dictionary ||= "simple"
|
||||||
|
available_dictionaries.include?(dictionary) ? dictionary : available_dictionaries.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def available_dictionaries
|
||||||
|
result = ActiveRecord::Base.connection.execute(SQL_QUERY)
|
||||||
|
result.to_a.map { |row| row["cfgname"] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1410,7 +1410,7 @@ describe "Proposals" do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "Order by relevance by default", :js do
|
scenario "Order by relevance by default", :spanish_search, :js do
|
||||||
create(:proposal, title: "Show you got", cached_votes_up: 10)
|
create(:proposal, title: "Show you got", cached_votes_up: 10)
|
||||||
create(:proposal, title: "Show what you got", cached_votes_up: 1)
|
create(:proposal, title: "Show what you got", cached_votes_up: 1)
|
||||||
create(:proposal, title: "Show you got", cached_votes_up: 100)
|
create(:proposal, title: "Show you got", cached_votes_up: 100)
|
||||||
|
|||||||
30
spec/lib/search_dictionary_selector_spec.rb
Normal file
30
spec/lib/search_dictionary_selector_spec.rb
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe SearchDictionarySelector do
|
||||||
|
context "from I18n default locale" do
|
||||||
|
before { allow(subject).to receive(:call).and_call_original }
|
||||||
|
around do |example|
|
||||||
|
original_i18n_default = I18n.default_locale
|
||||||
|
begin
|
||||||
|
example.run
|
||||||
|
ensure
|
||||||
|
I18n.default_locale = original_i18n_default
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns correct dictionary for simple locale" do
|
||||||
|
I18n.default_locale = :es
|
||||||
|
expect(subject.call).to eq("spanish")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns correct dictionary for compound locale" do
|
||||||
|
I18n.default_locale = :"pt-BR"
|
||||||
|
expect(subject.call).to eq("portuguese")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns simple for unsupported locale" do
|
||||||
|
expect(I18n).to receive(:default_locale).and_return(:pl) # avoiding I18n::InvalidLocale
|
||||||
|
expect(subject.call).to eq("simple")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -503,7 +503,7 @@ describe Debate do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "stemming" do
|
context "stemming" do
|
||||||
it "searches word stems" do
|
it "searches word stems in Spanish", :spanish_search do
|
||||||
debate = create(:debate, title: "limpiar")
|
debate = create(:debate, title: "limpiar")
|
||||||
|
|
||||||
results = Debate.search("limpiará")
|
results = Debate.search("limpiará")
|
||||||
|
|||||||
@@ -558,7 +558,7 @@ describe Proposal do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "case" do
|
context "case" do
|
||||||
it "searches case insensite" do
|
it "searches case insensitive" do
|
||||||
proposal = create(:proposal, title: "SHOUT")
|
proposal = create(:proposal, title: "SHOUT")
|
||||||
|
|
||||||
results = Proposal.search("shout")
|
results = Proposal.search("shout")
|
||||||
|
|||||||
@@ -128,6 +128,10 @@ RSpec.configure do |config|
|
|||||||
allow(Time).to receive(:zone).and_return(application_zone)
|
allow(Time).to receive(:zone).and_return(application_zone)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
config.before(:each, :spanish_search) do |example|
|
||||||
|
allow(SearchDictionarySelector).to receive(:call).and_return("spanish")
|
||||||
|
end
|
||||||
|
|
||||||
# Allows RSpec to persist some state between runs in order to support
|
# Allows RSpec to persist some state between runs in order to support
|
||||||
# the `--only-failures` and `--next-failure` CLI options.
|
# the `--only-failures` and `--next-failure` CLI options.
|
||||||
config.example_status_persistence_file_path = "spec/examples.txt"
|
config.example_status_persistence_file_path = "spec/examples.txt"
|
||||||
|
|||||||
Reference in New Issue
Block a user