Skip to main content

Custom Filter Method

Overview​

We can add a custom filter method to filter records based on specific criteria. This is useful when the default filtering options do not meet the requirements. The custom filter method can be defined using the filter_with option.

Usage​

The custom filter method is implemented using the filter dsl_method with the filter_with option. Below are the key elements and their usage:

Syntax​

filter :filter_name, :filter_type, filter_with: :custom_filter_method

Scope signature​

Filter typeScope arguments
:search(value)
:single_select, :multi_select(value, condition = nil)
:date, :range(value, condition = nil)

condition is the operator selected in Advanced Filters, for example is_not or greater_than. It is nil when the scope is called from the standard filter bar. For date and range filters, value is the raw string ("2026-01-01 to 2026-01-31", "18 to 30", or a single value such as "18").

warning

Lambda scopes enforce arity. A select, date, or range scope that does not accept condition raises ArgumentError.

Example​

1. For Search:

class YourModel < ApplicationRecord
scope :custom_filter_method, ->(value) { where('column_name ILIKE ?', "%#{value}%") }
end
filter :filter_name, :search, filter_with: :custom_filter_method

2. For Single / Multi Select:

class User < ApplicationRecord
scope :by_company_country, lambda { |value, condition = nil|
left_joins(:company).ct_dropdown_filter_condition(column: :country, value:, condition:, table: 'companies')
}
end
filter :company_country, :multi_select, helper_method: :company_country_options, filter_with: :by_company_country

3. For Date and Range:

class User < ApplicationRecord
scope :by_company_size, lambda { |value, condition = nil|
left_joins(:company).ct_range_filter_condition(column: :employee_count, value:, condition:, table: 'companies')
}
end
filter :company_size, :range, filter_with: :by_company_size

Condition helpers​

These helpers are available on every ActiveRecord model through CmAdmin::FilterConditions. table: defaults to the model's own table.

HelperHandles
ct_dropdown_filter_condition(column:, value:, condition:, table:)is, is_not, is_empty, is_not_empty. cm_empty maps to NULL
ct_range_filter_condition(column:, value:, condition:, table:)between, not_between, greater_than, less_than, greater_than_or_equal_to, less_than_or_equal_to, is, is_not, is_empty, is_not_empty

If you write the logic by hand instead, handle is_empty / is_not_empty. They are called with a blank value.