Skip to content
Roman Blanco edited this page Sep 8, 2022 · 16 revisions

Scoped search requires you to define the fields you want to search in:


class User < ActiveRecord::Base
  scoped_search on: :first_name
  scoped_search on: :last_name
end

Setting a field alias

It is possible to set a field alias, so that the alias can used in queries as well as the actual field name:


class User < ActiveRecord::Base
  scoped_search on: :username, aliases: [:login]
  scoped_search on: :last_name, aliases: [:surname, :name]
end

Renaming a field

It is possible to rename a field, so that the new name can be used in queries instead of the actual field name:


class User < ActiveRecord::Base
  scoped_search on: :username, rename: :login
end

Setting validations

Validation could be set for a field.
A validator is a lambda that receives the value as entered by the user and returns true if the value is valid for the field.
Note: the value would be used in an if statement, so everything that is not nil or false would be considered as true.

For convenience, there are two preset validators:

  • For integer values: ScopedSearch::Validators::INTEGER
  • For numeric values: ScopedSearch::Validators::NUMERIC

Examples:


class User < ActiveRecord::Base
  scoped_search on: :user_id, validator: ScopedSearch::Validators::INTEGER
  scoped_search on: :price, validator: ScopedSearch::Validators::NUMERIC
  scoped_search on: :predefined_text, validator: ->(value) { !!(value =~ /^(aa|bb|cc)$/) }
end

Setting the default operator

By default, scoped search uses the LIKE operator for textual fields, and the equals operator for other fields types. You can ovverride this behavior as follows:


class User < ActiveRecord::Base
  scoped_search on: :username, default_operator: :eq
end

Setting the default sort

By default, scoped search doesn’t sort the results of a query. You can override this behavior as follows:


class User < ActiveRecord::Base
  scoped_search on: :username, default_order: true
end

Only search a field if it is explicitly mentioned

By default, scoped search will search in every specified field if no explicit field is given in the query. You can specify that scoped search should only look in a field if it is explicitly mentioned in a query (e.g. username = root instead of root).


class User < ActiveRecord::Base
  scoped_search on: :username, only_explicit: true
end

Searching in relations

It is possible to search in fields of related tables as well. Every Rails relationship type is supported: i.e. has_many, belongs_to, has_one, has_and_belongs_to_many, has_many => :through.


class User < ActiveRecord::Base
  belongs_to :account_type
  has_and_belongs_to_many :groups

  scoped_search relation: :groups, on: :description
  scoped_search relation: :account_type, on: :name
end

For scoped_search 3.x and older, change `:relation` to `:in`.

Value Auto-completion

You can enable value auto-completion by adding :complete_value => true to the declaration line.


  scoped_search on: :title, complete_value: true

By default suggested values are drawn from the database. The user will be able to select from the list, or start typing to make the list shorter.

This solution fits many cases, but sometimes the possible values are a known set of values, that are not necessarily in the database. In that case you can specify a hash with human-readable labels and corresponding values and the database will not be consulted at all.


  scoped_search on: :status, complete_value: {offline: 0, online: 1, away: 2}

Value translation

Value translation allows certain values to be transformed when the search is performed. It can be enabled by adding the value_translation option to the declaration line. The value for this option should be a mapping function, which will be invoked during search with the value provided by the user. It has to return a value which will be used in the search, returning nil is not allowed. The user can also specify an array of special_values. Values specified there will automatically pass validation without having to be specified in the validator. The special values are also offered to the user during autocompletion.


  scoped_search relation: :user, on: :id,
                value_translation: ->(value) { value == 'current' ? User.current.id : value },
                validator: ->(value) { value =~ /[0-9]+/ }
                special_values: %w(current)

The snippet above will make search user.id = current translate to user.id = 4 (if the ID of the user executing the query is 4) which will then be evaluated.

Shorthand notation

As shorthand, you can use an array to specify multiple fields in one line using an array:


class User < ActiveRecord::Base
  scoped_search on: [:first_name, :last_name]
  scoped_search relation: :groups, on: [:name, :description]
end

External search methods

If you need to look for something that is not a column on your database, you might need to do some complicated query. In order to get scoped_search to understand these conditions, you can link to an static method that will return a hash with the conditions you need.

The following example would allow for searches like Person.search_for('house = johndoehouse').


class Person < ActiveRecord::Base
  has_many :houses  

  scoped_search in: :name
  scoped_search relation: :houses, on: :name, ext_method: :find_by_house

  def self.find_by_house(key, operator, value)
    conditions = sanitize_sql_for_conditions(["houses.name #{operator} ?", value_to_sql(operator, value)])
    owners = Person.joins(:houses).where(conditions).select('person.name').map(&:id)
    
    { :conditions => "person.name IN(#{owners.join(',')})" } 
  end
end

The method must return a hash containing any of these keys:

  • :conditions – string containing a SQL fragment, may optionally use ? placeholders
  • :parameter – array of parameters to be inserted into condition ? placeholders
  • :include – symbol, string or array of associations to be included in the scope (ActiveRecord::QueryMethods#includes)
  • :joins – symbol, string or array of model associations to join to (ActiveRecord::QueryMethods#joins)

To adjust the list of operators used for auto-completion:


scoped_search relation: :houses, on: :name, ext_method: :find_by_house, operators: ['=', '!=', '>', '<', '<=', '>=', '~', '!~', '^', '!^']

Backwards compatibility with 0.x, 1.x

For backwards compatibility, the following syntax to define fields is supported as well (prior to version 3.0.0). If you are still using this syntax, please migrate to the new version described above.


class User < ActiveRecord::Base
  has_many :groups
  searchable_on :first_name, :last_name, :groups_name, :groups_description
end