From 764c78e3b54770c2242c1e38e624793f689afe53 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Thu, 8 Feb 2018 10:23:16 +0100 Subject: [PATCH] Support multi-word last names in Principal#like and therefore User autocompleter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Principal#like query was handling firstname-lastname in a rather naïve way. Everything up until the last space was considered one name component, the rest was the other. But if - like e.g. in nobiliary names - the last name contains spaces, this leads to missed matches. With this patch we split the name at all spaces and search for all name tokens within both database name fields. --- app/models/principal.rb | 17 +++++++++++------ test/unit/principal_test.rb | 10 ++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/app/models/principal.rb b/app/models/principal.rb index e4410dde2..b2476c154 100644 --- a/app/models/principal.rb +++ b/app/models/principal.rb @@ -69,15 +69,20 @@ class Principal < ActiveRecord::Base where({}) else pattern = "%#{q}%" - sql = %w(login firstname lastname).map {|column| "LOWER(#{table_name}.#{column}) LIKE LOWER(:p)"}.join(" OR ") + sql = "LOWER(#{table_name}.login) LIKE LOWER(:p)" sql << " OR #{table_name}.id IN (SELECT user_id FROM #{EmailAddress.table_name} WHERE LOWER(address) LIKE LOWER(:p))" params = {:p => pattern} - if q =~ /^(.+)\s+(.+)$/ - a, b = "#{$1}%", "#{$2}%" - sql << " OR (LOWER(#{table_name}.firstname) LIKE LOWER(:a) AND LOWER(#{table_name}.lastname) LIKE LOWER(:b))" - sql << " OR (LOWER(#{table_name}.firstname) LIKE LOWER(:b) AND LOWER(#{table_name}.lastname) LIKE LOWER(:a))" - params.merge!(:a => a, :b => b) + + tokens = q.split(/\s+/).reject(&:blank?).map { |token| "%#{token}%" } + if tokens.present? + sql << ' OR (' + sql << tokens.map.with_index do |token, index| + params.merge!(:"token_#{index}" => token) + "(LOWER(#{table_name}.firstname) LIKE LOWER(:token_#{index}) OR LOWER(#{table_name}.lastname) LIKE LOWER(:token_#{index}))" + end.join(' AND ') + sql << ')' end + where(sql, params) end } diff --git a/test/unit/principal_test.rb b/test/unit/principal_test.rb index 2abd110f9..bb03a088e 100644 --- a/test/unit/principal_test.rb +++ b/test/unit/principal_test.rb @@ -127,6 +127,16 @@ class PrincipalTest < ActiveSupport::TestCase assert_equal User.find(2), results.first end + test "like scope should find lastname with spaces" do + user = User.find(1) + user.update_columns(:firstname => 'Leonardo', :lastname => 'da Vinci') + + results = Principal.like('Leonardo da Vinci') + + assert_equal 1, results.count + assert_equal user, results.first + end + def test_like_scope_with_cyrillic_name user = User.generate!(:firstname => 'Соболев', :lastname => 'Денис') results = Principal.like('Собо') -- 2.14.1