From 44f4befa5aca1ee3daeeb46285f8db433a6baf3b Mon Sep 17 00:00:00 2001 From: evazion Date: Mon, 27 Nov 2017 13:44:47 -0600 Subject: [PATCH] autocomplete: add automatic typo correction. If normal autocomplete fails to find any results, try doing a fuzzy name search instead. This will correct simple typos. --- app/assets/javascripts/autocomplete.js | 2 +- app/models/tag.rb | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/autocomplete.js b/app/assets/javascripts/autocomplete.js index 40279a8e6..3471b5de0 100644 --- a/app/assets/javascripts/autocomplete.js +++ b/app/assets/javascripts/autocomplete.js @@ -244,7 +244,7 @@ $.ajax({ url: "/tags/autocomplete.json", data: { - "search[name_matches]": term + "*" + "search[name_matches]": term }, method: "get", success: function(data) { diff --git a/app/models/tag.rb b/app/models/tag.rb index 5534c4b9c..7fdd56fed 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -890,21 +890,29 @@ class Tag < ApplicationRecord end def names_matches_with_aliases(name) - query1 = Tag.select("tags.name, tags.post_count, tags.category, null AS antecedent_name") - .search(:name_matches => name, :order => "count").limit(10) + name = normalize_name(name) + wildcard_name = name + '*' + + query1 = Tag.select("tags.name, tags.post_count, tags.category, null AS antecedent_name") + .search(:name_matches => wildcard_name, :order => "count").limit(10) - name = name.mb_chars.downcase.to_escaped_for_sql_like query2 = TagAlias.select("tags.name, tags.post_count, tags.category, tag_aliases.antecedent_name") .joins("INNER JOIN tags ON tags.name = tag_aliases.consequent_name") - .where("tag_aliases.antecedent_name LIKE ? ESCAPE E'\\\\'", name) + .where("tag_aliases.antecedent_name LIKE ? ESCAPE E'\\\\'", wildcard_name.to_escaped_for_sql_like) .active - .where("tags.name NOT LIKE ? ESCAPE E'\\\\'", name) + .where("tags.name NOT LIKE ? ESCAPE E'\\\\'", wildcard_name.to_escaped_for_sql_like) .where("tag_aliases.post_count > 0") .order("tag_aliases.post_count desc") .limit(20) # Get 20 records even though only 10 will be displayed in case some duplicates get filtered out. sql_query = "((#{query1.to_sql}) UNION ALL (#{query2.to_sql})) AS unioned_query" - Tag.select("DISTINCT ON (name, post_count) *").from(sql_query).order("post_count desc").limit(10) + tags = Tag.select("DISTINCT ON (name, post_count) *").from(sql_query).order("post_count desc").limit(10) + + if tags.empty? + tags = Tag.fuzzy_name_matches(name).order_similarity(name).nonempty.limit(10) + end + + tags end end