Dead simple, powerful and fully customizable searching for your Rails or ActiveRecord models and associations. Capable of searching any attribute type using SQL type casting.
Why This Library:
If you are considering using the ransack
gem, then you should think again because ransack
is a very dirty solution that completely integrates the Searching, Sorting, and Views as requirements of eachother. Not having these features separated hurts your ability to customize and modify your code. Don't fall into this trap. This gem is just one concern with one scope. If you want to customize it later you can simply copy the code directly into your project.
gem 'search_architect'
Then add include SearchArchitect
to your ApplicationRecord or models.
You can define any search scopes on your model using the following:
class Comment < ApplicationRecord
include SearchArchitect
has_many :comments
end
class Comment < ApplicationRecord
include SearchArchitect
belongs_to :user
belongs_to :post
end
class Post < ApplicationRecord
include SearchArchitect
has_many :comments
search_scope :search, attributes: [
:title,
:content,
:number, ### non-string fields are automatically converted to a searchable type using sql CAST method
"CAST((#{self.table_name}.number+100) AS CHAR)", ### Plain SQL fully supported
:created_at, ### automatically converts date/time fields to searchable string type using sql CAST method, uses default db output format by default
comments: [
:number,
:content,
user: [
"users.name",
comments: [
{table_alias: "users_comments"}, ### Must manually specify a table_alias when we have multiple associations referencing the same table
"users_comments.content",
],
]
],
]
search_scope :search_with_locale, sql_variables: [:locale], attributes: [
"#{self.table_name}.name_translations ->> :locale", # specify any variables as symbols, Ex. :locale
]
search_scope :search_custom_date_format, attributes: [
# PostgreSQL, Oracle
"TO_CHAR(#{self.table_name}.approved_at, 'YYYY-mm-dd')",
# MySQL
"DATE_FORMAT(#{self.table_name}.approved_at, '%Y-%m-%d')",
# SQLite
"strftime(#{self.table_name}.approved_at, '%Y-%m-%d')",
]
end
You would now have access to the following searching methods:
posts = Post.search(params[:search])
posts = Post.search_with_locale(params[:search], sql_variables: {locale: @current_locale})
We includes two different searching types:
Considers entire string as one search. In my experience this is the natural choice however the multi-search proves to be very powerful.
posts = Post.search(params[:search], search_type: :full_search)
### OR
posts = Post.search(params[:search]) # defaults to :full_search
Recommended. Split words on whitespace characters, Quoting is allowed to combine words
The following type of queries are supported:
foo
(rows must include foo)foo bar
(rows must include both foo and bar)"foo bar"
(rows must include the phrase "foo bar")
posts = Post.search(params[:search], search_type: :multi_search)
Different comparison operators can be specified by adding the :comparison_operator
argument
posts = Post.search(params[:search], comparison_operator: '=')
The default is ILIKE
if Postgresql or LIKE
if non-postgres. Current valid options are: ILIKE
, LIKE
, and =
- Most Types:
CAST(posts.number AS CHAR)
CAST(posts.created_at AS CHAR)
- uses default db output format by default
- Custom Date/Time Formatting:
- Postgresql, Oracle
TO_CHAR(posts.created_at, 'YYYY-mm-dd')
- MySQL
DATE_FORMAT(posts.created_at, '%Y-%m-%d')
- SQLite
strftime(posts.created_at, '%Y-%m-%d')
- Postgresql, Oracle
Boolean columns are only searched by their true/false value. Searching boolean fields by the column name is not possible because apparently SQL has the restriction where you cannot use CASE
statements within WHERE
clauses.
For example if you were trying to search a boolean
by the string of its column name:
CASE WHEN users.admin IS TRUE THEN 'admin' ELSE '' END
You will find it extremely difficult to work around this. Instead I strongly recommend handling your booleans filtering logic seperately from your search logic.
We do not provide built in view templates because this is a major restriction to applications. If your looking for starter template feel free to use the following example:
A key aspect of this library is its simplicity and small API. For major functionality customizations we encourage you to first delete this gem and then copy this gems code directly into your repository.
I strongly encourage you to read the code for this library to understand how it works within your project so that you are capable of customizing the functionality later.
Created & Maintained by Weston Ganger - @westonganger