Class: ActiveRecord::Base

Inherits:
Object show all
Defined in:
lib/ultrasphinx/is_indexed.rb

Class Method Summary collapse

Class Method Details

.is_indexed(opts = {}) ⇒ Object

The is_indexed macro configures a model for indexing. Its parameters are used to generate SQL queries for Sphinx.

Indexing single fields

Use the :fields key.

Accepts an array of field names.

:fields => ["created_at", "title", "body"]

Indexing fields from belongs_to associations

Use the :includes key.

Accepts an array of hashes.

Each should contain a :model key (the class name of the included model), a :field key (the name of the field to include), and an optional :as key (what to name the field in the parent). You can use the optional key :association_sql if you need to pass a custom JOIN string, in which case the default JOIN will not be generated.

Scoping the searchable records

Use the :conditions key.

SQL conditions, to scope which records are selected for indexing. Accepts a string.

:conditions => "created_at < NOW() AND deleted IS NOT NULL"

The :conditions key is especially useful if you delete records by marking them deleted rather than removing them from the database.

Concatenating multiple fields

Use the :concats key (MySQL only).

Accepts an array of option hashes, which can be of two types:

  1. To concatenate many fields within one record, use a regular (or horizontal) concatenation. Regular concatenations contain a :fields key (again, an array of field names), and a mandatory :as key (the name of the result of the concatenation). For example, to concatenate the title and body into one field called text:

:concats => [{:fields => ["title", "body"], :as => "text"}]
  1. To group and concatenate a field from a set of associated records, use a group (or vertical) concatenation. Group concatenations join into another table, and can be used to index a number of associated models as one field in a parent model. Group concatenations contain a :model key (the class name of the included model), a :field key (the field on the included model to concatenate), and an optional :as key (also the name of the result of the concatenation). For example, to concatenate all Post#body contents into the parent’s responses field:

:concats => {:model => "Post", :field => "body", :as => "responses"}

Optional group concatenation keys are :association_name (if your has_many association can’t be derived from the model name), :association_sql, if you need to pass a custom JOIN string (for example, a double JOIN for a has_many :through), and :conditions (if you need custom WHERE conditions for this particular association).

Example

Here’s an example configuration using most of the options, taken from production code:

class Story < ActiveRecord::Base  
  is_indexed :fields => [
      "title", 
      "published_at"
    ],
    :includes => [
      {:model => "Category", :field => "name", :as => "category"}
    ],      
    :concats => [
      {:fields => ["title", "long_description", "short_description"], :as => "editorial"},
      {:model => "Page", :field => "body", :as => "body", :association_name => "pages"},
      {:model => "Comment", :field => "body", :as => "comments", 
        :conditions => "comments.item_type = '#{base_class}'"}
    ],
    :conditions => self.live_condition_string
end


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/ultrasphinx/is_indexed.rb', line 71

def self.is_indexed opts = {}

  opts.assert_valid_keys [:fields, :concats, :conditions, :includes, :nulls]
  
  Array(opts[:concats]).each do |concat|
    concat.assert_valid_keys [:model, :conditions, :field, :as, :fields, :association_name, :association_sql]
    raise Ultrasphinx::ConfigurationError, "You can't mix regular concat and group concats" if concat[:fields] and (concat[:field] or concat[:model] or concat[:association_name])
    raise Ultrasphinx::ConfigurationError, "Group concats must not have multiple fields" if concat[:field].is_a? Array
    raise Ultrasphinx::ConfigurationError, "Regular concats should have multiple fields" if concat[:fields] and !concat[:fields].is_a?(Array)
  end
  
  Array(opts[:joins]).each do |join|
    join.assert_valid_keys [:model, :field, :as]
  end
  
  Ultrasphinx::MODEL_CONFIGURATION[self.name] = opts
end