Project

kiroshi

0.0
The project is in a healthy, maintained state
Kiroshi
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

>= 3.0.0
 Project Readme

Kiroshi

Build Status Codacy Badge

kiroshi

Yard Documentation

https://www.rubydoc.info/gems/kiroshi/0.3.1

Kiroshi has been designed to make filtering ActiveRecord queries easier by providing a flexible and reusable filtering system. It allows you to define filter sets that can be applied to any ActiveRecord scope, supporting both exact matches and partial matching using SQL LIKE operations.

Current Release: 0.3.1

Next release

Installation

  • Install it
  gem install kiroshi
  • Or add Kiroshi to your Gemfile and bundle install:
  gem 'kiroshi'
  bundle install kiroshi

Usage

Kiroshi::Filters

Filters is a base class for implementing filter sets on ActiveRecord scopes. It uses a class-level DSL to define filters and an instance-level interface to apply them.

Basic Usage

# Define a filter class
class DocumentFilters < Kiroshi::Filters
  filter_by :name, match: :like
  filter_by :status
  filter_by :category
end

# Apply filters to a scope
filters = DocumentFilters.new(name: 'report', status: 'published')
filtered_documents = filters.apply(Document.all)
# Generates: WHERE name LIKE '%report%' AND status = 'published'

Filter Types

Kiroshi supports two types of matching:

  • :exact - Exact match (default)
  • :like - Partial match using SQL LIKE
Specifying filter types
class UserFilters < Kiroshi::Filters
  filter_by :email, match: :like      # Partial matching
  filter_by :role                     # Exact matching (default)
  filter_by :active, match: :exact    # Explicit exact matching
end

filters = UserFilters.new(email: 'admin', role: 'moderator')
filtered_users = filters.apply(User.all)
# Generates: WHERE email LIKE '%admin%' AND role = 'moderator'

Advanced Examples

Multiple Filter Types
Applying only some filters
class ProductFilters < Kiroshi::Filters
  filter_by :name, match: :like
  filter_by :category
  filter_by :price, match: :exact
  filter_by :brand
end

# Apply only some filters
filters = ProductFilters.new(name: 'laptop', category: 'electronics')
products = filters.apply(Product.all)
# Only name and category filters are applied, price and brand are ignored
Controller Integration
Using filters in Rails controllers
# URL: /documents?filter[name]=report&filter[status]=published&filter[author]=john
class DocumentsController < ApplicationController
  def index
    @documents = document_filters.apply(Document.all)
    render json: @documents
  end

  private

  def document_filters
    DocumentFilters.new(filter_params)
  end

  def filter_params
    params[:filter]&.permit(:name, :status, :category, :author)
  end
end

class DocumentFilters < Kiroshi::Filters
  filter_by :name, match: :like
  filter_by :status
  filter_by :category
  filter_by :author, match: :like
end
Nested Resource Filtering
Filtering nested resources
# URL: /users/123/articles?filter[title]=ruby&filter[published]=true&filter[tag]=tutorial
class ArticleFilters < Kiroshi::Filters
  filter_by :title, match: :like
  filter_by :published
  filter_by :tag, match: :like
end

# In your controller
def articles
  base_scope = current_user.articles
  article_filters.apply(base_scope)
end

def article_filters
  ArticleFilters.new(params[:filter]&.permit(:title, :published, :tag))
end
Joined Tables and Table Qualification
Working with joined tables

When working with joined tables that have columns with the same name, you can specify which table to filter on using the table parameter:

class DocumentFilters < Kiroshi::Filters
  filter_by :name, match: :like                    # Filters by documents.name (default table)
  filter_by :tag_name, match: :like, table: :tags  # Filters by tags.name
  filter_by :status                                # Filters by documents.status
  filter_by :category, table: :documents           # Explicitly filter by documents.category
end

# Example with joined scope
scope = Document.joins(:tags)
filters = DocumentFilters.new(tag_name: 'ruby', status: 'published')
filtered_documents = filters.apply(scope)
# Generates: WHERE tags.name LIKE '%ruby%' AND documents.status = 'published'
Table Qualification Examples
Advanced table qualification scenarios
# Filter documents by tag name and document status
class DocumentTagFilters < Kiroshi::Filters
  filter_by :tag_name, match: :like, table: :tags  # Search in tags.name
  filter_by :status, table: :documents             # Search in documents.status
  filter_by :title, match: :like                   # Search in documents.title (default table)
end

scope = Document.joins(:tags)
filters = DocumentTagFilters.new(tag_name: 'programming', status: 'published', title: 'Ruby')
result = filters.apply(scope)
# Generates: WHERE tags.name LIKE '%programming%' AND documents.status = 'published' AND documents.title LIKE '%Ruby%'

# Filter by both document and tag attributes with different field names
class AdvancedDocumentFilters < Kiroshi::Filters
  filter_by :title, match: :like, table: :documents
  filter_by :tag_name, match: :like, table: :tags
  filter_by :category, table: :documents
  filter_by :tag_color, table: :tags
end

scope = Document.joins(:tags)
filters = AdvancedDocumentFilters.new(
  title: 'Ruby', 
  tag_name: 'tutorial', 
  category: 'programming',
  tag_color: 'blue'
)
result = filters.apply(scope)
# Generates: WHERE documents.title LIKE '%Ruby%' AND tags.name LIKE '%tutorial%' AND documents.category = 'programming' AND tags.color = 'blue'

The table parameter accepts both symbols and strings, and helps resolve column name ambiguity in complex joined queries.

Custom Column Mapping
Using different filter keys from database columns

Sometimes you may want to use a different filter key name from the database column name. The column parameter allows you to specify which database column to query while keeping a descriptive filter key:

class UserFilters < Kiroshi::Filters
  filter_by :full_name, column: :name, match: :like      # Filter key 'full_name' queries 'name' column
  filter_by :user_email, column: :email, match: :like    # Filter key 'user_email' queries 'email' column  
  filter_by :account_status, column: :status             # Filter key 'account_status' queries 'status' column
end

filters = UserFilters.new(full_name: 'John', user_email: 'admin', account_status: 'active')
result = filters.apply(User.all)
# Generates: WHERE name LIKE '%John%' AND email LIKE '%admin%' AND status = 'active'
Column Mapping with Table Qualification
Combining column mapping with table qualification

You can combine column and table parameters for complex scenarios:

class DocumentFilters < Kiroshi::Filters
  filter_by :author_name, column: :name, table: :users, match: :like  # Filter key 'author_name' queries 'users.name'
  filter_by :doc_title, column: :title, table: :documents, match: :like  # Filter key 'doc_title' queries 'documents.title'
  filter_by :tag_label, column: :name, table: :tags, match: :like     # Filter key 'tag_label' queries 'tags.name'
end

scope = Document.joins(:user, :tags)
filters = DocumentFilters.new(author_name: 'John', doc_title: 'Ruby', tag_label: 'tutorial')
result = filters.apply(scope)
# Generates: WHERE users.name LIKE '%John%' AND documents.title LIKE '%Ruby%' AND tags.name LIKE '%tutorial%'

This feature is particularly useful when:

  • Creating more descriptive filter parameter names for APIs
  • Avoiding naming conflicts between filter keys and existing method names
  • Building user-friendly filter interfaces with intuitive parameter names

API Reference

Kiroshi provides a simple, clean API focused on the Kiroshi::Filters class. Individual filters are handled internally and don't require direct interaction in most use cases.