app/controllers/dry_crud/searchable.rb
module DryCrud
# The search functionality for the index table.
# Define an array of searchable string columns in your subclassing
# controllers using the class attribute +search_columns+.
module Searchable
extend ActiveSupport::Concern
included do
class_attribute :search_columns
self.search_columns = []
helper_method :search_support?
prepend Prepends
end
# Prepended methods for searching.
module Prepends
private
# Enhance the list entries with an optional search criteria
def list_entries
super.where(search_conditions)
end
# Concat the word clauses with AND.
def search_conditions
if search_support? && params[:q].present?
search_word_conditions.reduce do |query, condition|
query.and(condition)
end
end
end
# Split the search query in single words and create a list of word
# clauses.
def search_word_conditions
params[:q].split(/\s+/).map { |w| search_word_condition(w) }
end
# Concat the column queries of the given word with OR.
def search_word_condition(word)
search_column_condition(word).reduce do |query, condition|
query.or(condition)
end
end
# Create a list of Arel #matches queries for each column and the given
# word.
def search_column_condition(word)
self.class.search_tables_and_fields.map do |table_name, field|
table = Arel::Table.new(table_name)
table[field].matches(Arel::Nodes::Quoted.new("%#{word}%"))
end
end
# Returns true if this controller has searchable columns.
def search_support?
search_columns.present?
end
end
# Class methods for Searchable.
module ClassMethods
# All search columns divided in table and field names.
def search_tables_and_fields
@search_tables_and_fields ||= search_columns.map do |f|
if f.to_s.include?('.')
f.split('.', 2)
else
[model_class.table_name, f]
end
end
end
end
end
end