ActiveModel Integration

When you want a familiar way to populate and search your index without even need to know elasticsearch or when the data you have to index is external to your app (for example if you crawl a site and want to build a searchable index out of it), you can just manage the index like you were managing any active model, still keeping the searching capability of Flex::Scopes and/or Flex::Templates.

Notice: The result returned by querying elasticsearch with a Flex::ActiveModel model, return always regular instance of your class, not the original elasticsearch result structure. However you can always get the raw result by just calling raw_result on the array collection or any model instance.

The key concept is that you create a model per (elasticsearch) type, similarly to what you would do with a DB: a model per table/collection. You do so by including Flex::ActiveModel which also includes Flex::ModelIndexer, so you will have all the flex.* methods available both at the class level and at the instance level (see Flex::ModelIndexer).

Then you declare the model attributes names, and optionally their default and typecasting. You can eventually set also the elasticsearch mapping properties for each attribute that may need it, and you can use it as any other model. For example:

class Product
  include Flex::ActiveModel

  # if we omit the next line, the elasticsearch type would have been 'product' by default
  flex.type = 'goods'

  attribute :name
  # optional elasticsearch properties mapping
  attribute :price, :properties => {'type' => 'float'}, :default => 0

  # :analyzed => false is a shortcut to :properties => { 'type' => 'string', 'index' => 'not_analyzed' }
  attribute :color, :analyzed => false

  # this adds a :created_at and :updated_at attributes
  attribute_timestamps

  # standard validation
  validate :name, :presence => true

  # standard callback
  before_create { self.name = name.titleize }

  # named scope
  scope :red, term(:color => 'red')

end

# indexes the data in elasticsearch
product = Product.new :name  => 'my_name',
                      :color => 'blue',
                      :price => 9.99

product.save if product.valid?

red_products = Product.red.all
product = Product.find('a09rf')
total   = Product.count

Capabilities

By including Flex::ActiveModel your model gets the following capabilities:

Validation

Validation is provided verbatim by ActiveModel (see activemodel) so you an use all its standard validation methods.

Callbacks

Flex::ActiveModel provides the create, update, save and destroy callbacks backed by ActiveModel, so you can use them as usual with the before_* and after_* prefixes.

Attributes

By including Flex::ActiveModel you include also the ActiveAttr::Model. It provides a lot of useful goodies, like attribute declarations with defaults and typecasting (see active_attr). Besides, flex extends it with a few features (see Class Methods)

Versioning and optimistic lock updating

Flex::ActiveModel adds the versioning to your models (see elasticsearch Versioning, so your model has always a _version attribute. Besides, it implements the lock updating throught the method lock_update (see Safe Update).

Finders, Scopes and Templates

Flex::ActiveModel includes also the Flex::Scopes by default, so you have all the cool finders and chainable scopes ready to use in your model (see flex-scopes)

Besides, if you need more power to easily write complex queries, you can include the Flex::Templates module and use it as usual (see Templating)

Methods

(see Flex::ActiveModel, Flex::ModelIndexer and Flex::ModelSyncer)