Fixed bug: Organization search queries don't find case insensitive results.
This commit is contained in:
parent
61aa8fb84a
commit
809a698c03
4 changed files with 67 additions and 6 deletions
|
@ -17,6 +17,7 @@ class ApplicationModel < ActiveRecord::Base
|
||||||
include ApplicationModel::HasExternalSync
|
include ApplicationModel::HasExternalSync
|
||||||
include ApplicationModel::ChecksImport
|
include ApplicationModel::ChecksImport
|
||||||
include ApplicationModel::CanTouchReferences
|
include ApplicationModel::CanTouchReferences
|
||||||
|
include ApplicationModel::CanQueryCaseInsensitiveWhereOrSql
|
||||||
|
|
||||||
self.abstract_class = true
|
self.abstract_class = true
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
module ApplicationModel::CanQueryCaseInsensitiveWhereOrSql
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
|
||||||
|
# Builds a case insenstive WHERE ... OR ... SQL query.
|
||||||
|
#
|
||||||
|
# @see .or_cis
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# Organization.where_or_cis(%i[name note], "%zammad%").to_sql
|
||||||
|
# #=> "SELECT `organizations`.* FROM `organizations` WHERE (`organizations`.`name` LIKE '%zammad%' OR `organizations`.`note` LIKE '%zammad%')"
|
||||||
|
#
|
||||||
|
# @return [ActiveRecord::Relation] the ActiveRecord relation that can be combined or executed
|
||||||
|
scope :where_or_cis, ->(*args) { where(or_cis(*args)) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# methods defined here are going to extend the class, not the instance of it
|
||||||
|
class_methods do
|
||||||
|
|
||||||
|
# Builds a case insenstive OR SQL grouping. This comes in handy for join queries.
|
||||||
|
# For direct WHERE queries prefer .where_or_cis scope.
|
||||||
|
#
|
||||||
|
# @param [Array] attributes the attributes that should get queried case insensitive.
|
||||||
|
# @param [String] query the SQL query that should be used for each given attribute.
|
||||||
|
#
|
||||||
|
# @example
|
||||||
|
# Organization.joins(:users).where(User.or_cis(%i[firstname lastname email], "%#{query}%"))
|
||||||
|
#
|
||||||
|
# @return [Arel::Nodes::Grouping] can be passed to ActiveRecord queries
|
||||||
|
def or_cis(attributes, query)
|
||||||
|
# use Arel to create an Array of case insenstive
|
||||||
|
# LIKE queries based on the current DB adapter
|
||||||
|
cis_matches = attributes.map do |attribute|
|
||||||
|
arel_table[attribute].matches(query)
|
||||||
|
end
|
||||||
|
|
||||||
|
# return the by OR joined Arel queries
|
||||||
|
cis_matches.inject(:or)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -77,9 +77,11 @@ returns
|
||||||
# fallback do sql query
|
# fallback do sql query
|
||||||
# - stip out * we already search for *query* -
|
# - stip out * we already search for *query* -
|
||||||
query.delete! '*'
|
query.delete! '*'
|
||||||
organizations = Organization.where(
|
organizations = Organization.where_or_cis(%i[name note], "%#{query}%")
|
||||||
'name LIKE ? OR note LIKE ?', "%#{query}%", "%#{query}%"
|
.order('name')
|
||||||
).order('name').offset(offset).limit(limit).to_a
|
.offset(offset)
|
||||||
|
.limit(limit)
|
||||||
|
.to_a
|
||||||
|
|
||||||
# use result independent of size if an explicit offset is given
|
# use result independent of size if an explicit offset is given
|
||||||
# this is the case for e.g. paginated searches
|
# this is the case for e.g. paginated searches
|
||||||
|
@ -87,9 +89,11 @@ returns
|
||||||
return organizations if organizations.length > 3
|
return organizations if organizations.length > 3
|
||||||
|
|
||||||
# if only a few organizations are found, search for names of users
|
# if only a few organizations are found, search for names of users
|
||||||
organizations_by_user = Organization.select('DISTINCT(organizations.id), organizations.name').joins('LEFT OUTER JOIN users ON users.organization_id = organizations.id').where(
|
organizations_by_user = Organization.select('DISTINCT(organizations.id), organizations.name')
|
||||||
'users.firstname LIKE ? or users.lastname LIKE ? or users.email LIKE ?', "%#{query}%", "%#{query}%", "%#{query}%"
|
.joins('LEFT OUTER JOIN users ON users.organization_id = organizations.id')
|
||||||
).order('organizations.name').limit(limit)
|
.where(User.or_cis(%i[firstname lastname email], "%#{query}%"))
|
||||||
|
.order('organizations.name')
|
||||||
|
.limit(limit)
|
||||||
|
|
||||||
organizations_by_user.each do |organization_by_user|
|
organizations_by_user.each do |organization_by_user|
|
||||||
|
|
||||||
|
|
13
spec/models/organization_spec.rb
Normal file
13
spec/models/organization_spec.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Organization do
|
||||||
|
|
||||||
|
context '.where_or_cis' do
|
||||||
|
|
||||||
|
it 'finds instance by querying multiple attributes case insensitive' do
|
||||||
|
# search for Zammad Foundation
|
||||||
|
organizations = described_class.where_or_cis(%i[name note], '%zammad%')
|
||||||
|
expect(organizations).not_to be_blank
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue