-
Notifications
You must be signed in to change notification settings - Fork 532
Data storage in Tire and wrapping the results
There's been a fair bit of discussion regarding the way Tire should retrieve objects from elasticsearch (ES) and present them to your Ruby code. Ultimately, there is no one correct way to do this due to the very different use cases that exist. Fortunately, Tire gives you a couple of options to customise the way this should be handled. This page serves as a summary of the different ways that you can use Tire to store and retrieve your data and the options available to the developer for wrapping the results.
First and foremost, any data you retrieve from ES using Tire will be an instance of Tire::Results::Item
. This is the default behaviour of Tire. (see source). They are fairly straight forward objects, they simply map whatever fields are returned from ES to corresponding attributes. Basically, they are a very thin wrapper around nested hashes representing the data returned from ES.
This is the most lightweight way to use Tire/ES in your Ruby code. Simply include the gem, store some objects and retrieve them by id
or by querying (or query another existing ES index that is not necessarily part of your application).
Note that this way you are working completely agnostic of document types, you are simply searching through the entire index and getting generic Item
objects/hashes.
For use in Rails (and potentially other frameworks) Tire::Results::Item
is extended with the ActiveModel::Naming
module (Tire lists ActiveModel as a library dependency). This allows for naming, routing and using view templates. The instances of Item
trick Rails in thinking it is a different class by overriding the #class
method as such:
def class
defined?(::Rails) && @attributes[:_type] ? @attributes[:_type].camelize.constantize : super
rescue NameError
super
end
It attempts to deduce the correct (ActiveRecord) class and document type from the _type
attribute in ES. If that is not present, or we are not in Rails it will just return super
, which will default to Tire::Results::Item
.
If you are using Rails, Tire will trick Rails into thinking it is actually returning your ActiveRecord objects:
> s = Article.search "title:*"
> item = s.results.first
> item.class
=> Article
This is done by Tire to make sure that all the standard Rails helpers will work and allow you to, for example, do routing with your objects. Things like article_path @article
will just work in your views (where @article
is a result coming from ES).
Note that as of this momentTire::Results::Item
does not override the is_a?
method, so if you're using that to check what kind of an object you're dealing with you need to be prepared for that:
> item.class
=> Article
> item.is_a? Article
=> false
For more discussion on this subject, see issue #159.
A different way to use Tire is to use ES as your main data store, skipping the regular ActiveRecord options (such as MySQL, SQLite, etc.). For this Tire provides the Tire::Model::Persistence
module. It includes all the ActiveModel requirements and provides callbacks and search functionality for your data models. Storing your models in ES would then be as easy as:
> a = Article.new(:title => "My interesting article")
> a.save
The simplest class definition for this would look something like:
class Article
include Tire::Model::Persistence
property :title
end
Note that this is not limited to Rails applications, you can use this in whatever project you like (Rack, plain Ruby, whatever). The resulting object will be a valid ActiveModel object, so if you are using Rails all the standard options for ActiveModel objects are available to you (again: the routing, view templates, etc.).
- General info on why you would do such a thing
- Using an object inheriting from
SimpleDelegator