-
Notifications
You must be signed in to change notification settings - Fork 532
Using Tire with Draper
There's many reasons for wanting to augment either the Collection or the Item returned by Tire.
For example:
- Add additional view logic that you don't want to put in a helper
- Reuse view logic between ActiveRecord/Mongoid & Tire.
- Just to add additional methods to the collection or item.
You can do this using Draper which provides View-Models/Decorators.
There's two ways to go about it.
We could define just a ordinary Draper::Decorator
:
class Article < ActiveRecord::Base
include Tire::Model::Search
include Tire::Model::Callbacks
end
class ArticleDecorator < Draper::Decorator
# We can either delegate all methods not defined in our decorator
# or just specific methods that we want to pass on to the Tire::Results::Item instance.
delegate_all
def caption
source.title + '-' + source.description
end
end
We can then use it like this
articles = Article.search(query: 'something')
decorated_articles = ArticleDecorator.decorate_collection(articles)
That would give us an instance of Draper::CollectionDecorator
which is the default collection decorator in Draper.
So we could then do:
decorated_articles.first.name
=> 'The name'
However, what we cannot do with this approach is to get to any facets or other methods defined on the Tire::Results::Collection
object.
decorated_articles.facets
=> NoMethodError: undefined method `facets' for #<Draper::CollectionDecorator:0x007f836d9888f0>
That's because the default collection decorator does not automatically delegate those methods to the source Tire::Search::Collection
instance. So if we don't need to access those properties, we are fine with this method.
We also need to define a Draper::CollectionDecorator
ArticlesDecorator < Draper::CollectionDecorator
# There's no delegate_all here so we'll need to delegate each
# methods we want to pass on to the Tire::Search::Collection
delegate :facets
def some_method_that_deals_with_the_collection
# we can access the Tire::Search::Collection instance via the method source.
'something'
end
end
We can now use this collection decorator directly to decorate both the collection and the items. Draper will automatically look for a decorator named ArticleDecorator
, loop through our hits and wrap them with it.
articles = Article.search(query: 'Draper')
decorated_articles = ArticlesDecorator.new(articles)
# We can now access the method we delegated
decorated_articles.facets
=> { hash with the facets }
# Or the ones we defined in our ArticlesDecorator
decorated_articles.some_method_that_deals_with_the_collection
=> 'something'
decorated_articles.first.caption
=> 'Using Tire with Draper - To augment Collection and Item'
# We also still have the methods from Tire::Results::Item at arms length
since we used delegate_all in our ArticleDecorator.
decorated_articles.first._score
=> '0.30685282'
We can now reuse our view models between Tire and ActiveRecord/Mongoid, as long as they adhere to the same interface (attributes).
For more information on draper, read the Draper readme