Last active
          May 26, 2025 16:48 
        
      - 
      
- 
        Save bhserna/be69f7d688bda8bc02d92fbc5defe509 to your computer and use it in GitHub Desktop. 
    A concern to easily add search to a rails model using LIKE (only tested on sqlite)
  
        
  
    
      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
    
  
  
    
  | # You can search on columns of the record or on associations | |
| # Example of a search on the record's column | |
| class Brand < ApplicationRecord | |
| include Searchable | |
| # All this are columns on the Brand record | |
| search_on :id, :name, :description | |
| end | |
| class BrandsController < ApplicationController | |
| def index | |
| # maybe_search will execute the search only if the query is present | |
| @brands = Brand.maybe_search(params[:query]) | |
| end | |
| end | |
| # Example of a search on the record's column and associations | |
| class Quote < ApplicationRecord | |
| include Searchable | |
| belongs_to :client | |
| belongs_to :requester, class_name: "Contact" | |
| has_many :quote_items, dependent: :destroy | |
| has_many :notes, as: :notable, dependent: :destroy | |
| search_on :id, :sequence_id, :external_id, :custom_id, :general_conditions, | |
| client: [:name], | |
| requester: [:full_name, :current_company], | |
| quote_items: [:product_name, :part_number, :description], | |
| notes: [:content] | |
| end | |
| class QuotesController < ApplicationController | |
| def index | |
| @quotes = Quote.maybe_search(params[:query]) | |
| 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
    
  
  
    
  | module Searchable | |
| extend ActiveSupport::Concern | |
| included do | |
| cattr_accessor :searchable_fields, :searchable_associations_fields | |
| end | |
| class_methods do | |
| def search_on(*searchable_fields, **searchable_associations_fields) | |
| self.searchable_fields = searchable_fields | |
| self.searchable_associations_fields = searchable_associations_fields | |
| scope :search, ->(query) do | |
| left_outer_joins(searchable_joins).where(searchable_where_clause, query: "%#{query}%").distinct | |
| end | |
| scope :maybe_search, ->(query) do | |
| search(query) if query.present? | |
| end | |
| end | |
| def searchable_joins | |
| searchable_associations_fields.keys | |
| end | |
| def searchable_where_clause | |
| all_normalized_searchable_fields.map { |field| "#{field} LIKE :query" }.join(" OR ") | |
| end | |
| def all_normalized_searchable_fields | |
| normalized_searchable_fields + normalized_searchable_associations_fields | |
| end | |
| def normalized_searchable_fields | |
| searchable_fields.map { |field| [table_name, field].join(".") } | |
| end | |
| def normalized_searchable_associations_fields | |
| searchable_associations_fields.flat_map do |association, fields| | |
| table_name = reflect_on_association(association).klass.table_name | |
| Array.wrap(fields).map { |field| [table_name, field].join(".") } | |
| end | |
| end | |
| end | |
| end | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment