Last active
September 7, 2015 16:42
-
-
Save jimworm/35833846e851afec31ab to your computer and use it in GitHub Desktop.
Rails: search for members of a model using its columns or columns of related models, SQL-only
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Searchable | |
extend ActiveSupport::Concern | |
module ClassMethods | |
def searchable(*args) | |
class_attribute :searchable_attributes | |
self.searchable_attributes = args | |
end | |
def search(search_string, limit=100) | |
return find(:all) if search_string.nil? || search_string.blank? | |
query = self.except(:includes) | |
attrs = searchable_attributes.dup | |
searchable_columns = [] | |
if attrs.last.is_a? Hash | |
related = attrs.pop | |
related.each_pair do |relationship, column_names| | |
relative = reflections.with_indifferent_access[relationship] | |
fail 'Cannot search polymorphic relationships' if relative.options[:polymorphic] | |
searchable_columns += column_names.map{|column_name| "`#{relative.table_name}`.`#{column_name.to_s}`"} | |
query = case relative.source_macro | |
when :belongs_to | |
query.joins("LEFT OUTER JOIN `#{relative.table_name}` ON `#{table_name}`.`#{relative.foreign_key}` = `#{relative.table_name}`.`#{relative.association_primary_key}`") | |
when :has_many, :has_one | |
query.joins("LEFT OUTER JOIN `#{relative.table_name}` ON `#{relative.table_name}`.`#{relative.foreign_key}` = `#{table_name}`.`#{relative.association_primary_key}`") | |
else | |
fail 'Can only search direct relationships' | |
end | |
end | |
end | |
searchable_columns += attrs.map {|a| "`#{table_name}`.`#{a.to_s}`" } | |
query = query.select(["`#{table_name}`.`#{primary_key}`", "concat_ws(' ', #{searchable_columns.join(', ')}) as searchable_fields"]) | |
search_string.split(' ').each do |s| | |
query = query.having("searchable_fields LIKE ?", "%#{s.strip.gsub(/[%_]/){|x|'\\'+x}}%") | |
end | |
self.where("`#{table_name}`.`#{primary_key}` in (SELECT #{primary_key} FROM (#{query.to_sql}) AS searchable_temp)") | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class User < ActiveRecord::Base | |
# example of use | |
include Searchable | |
belongs_to :employer | |
has_many :houses | |
has_many :cars | |
searchable :forenames, :surname, employer: [:name], houses: [:name, :address, :telephone], cars: [:name, :licence_plate] | |
end | |
# Who is the guy parked at BigCorp that scratched my car? | |
# User.search('BigCorp LIC1234') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment