No commit activity in last 3 years
No release in over 3 years
Adds GitHub-like search function to your models
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

< 5, >= 4.0
 Project Readme

Acts As Explorable

Gem Version Build Status Code Climate Inline docs

Acts As Explorable extends ActiveRecord models with a search class method. This method can be fed with a quer like Madrid in:city position:MF sort:club. Which means "Get all players who play in Madrid on the midfielder position and sort the results by the club names".

Acts As Explorable is a Ruby Gem specifically written for ActiveRecord models. It uses Arel to build query parts.

Installation

Supported Ruby and Rails versions

  • Ruby 2.0.0, 2.1.0
  • Rails 4.0, 4.1, 4.2+

Install

Just add the following to your Gemfile.

gem 'acts_as_explorable', '~> 0.1.1'

And follow that up with a bundle install.

Usage

To enable the explorable plugin, just include the following lines into your model:

class Foo < ActiveRecord::Base
  extend ActsAsExplorable
  explorable
end

Now you have the .search method on your model, which can be invoked like

Foo.search('Awesome in:bar')

A query string consists of two different types: The values (random words) and filters (starting with a word followed by a : and again a word -> in:bar). As of writing this, there are three different kinds of filters.

Filters

A filter always consists of an element (the string before the :) and the "modifiers", which can be appended with a ,. Optional you can add a - for options (only used in sort: at the moment).

In

The in: filter makes use of the values given in the query string. It looks up these values in the given columns. For example the following query will look up all posts with the word "Zlatan" in the title or the body:

Zlatan in:title,body

You can do that by defining the in: filter on your model:

class Post < ActiveRecord::Base
  extend ActsAsExplorable
  explorable in: [:title, :body]
end

As you see, it is possible to look up the value in different columns. This generates some SQL like:

SELECT posts.* FROM posts 
  WHERE (posts.title ILIKE '%Zlatan%' OR posts.body ILIKE '%Zlatan%') 

Sort

The sort: filter does (guess what?!) sorting. Just write sort: followed by the columns you want to sort. You can also append a -desc or -asc for the direction. So the query sort:created_at-asc sorts all posts be the created_at column in ascending direction.

Just define the sort: filter for your model:

class Player < ActiveRecord::Base
  extend ActsAsExplorable
  explorable sort: [:title, :created_at]
end

You can add more sorts just by addding the with a comma. sort:created_at-asc,title-desc. This produces the following SQL:

SELECT posts.* FROM posts 
  ORDER BY posts.created_at ASC, posts.title DESC

Dynamic Filters

This is where the "magic" happens. Say you have a model that represents a football player. And this player plays on a specific position. If you want to find all midfielders you could do MF in:position or you could use a dynamic filter.

You can define these filters on your model and assign options to them like this:

class Player < ActiveRecord::Base
  extend ActsAsExplorable
  explorable position: ['GK', 'DF', 'MF', 'FW']
end

Now, given a quer string position:MF,FW will give you all midfielders an forwards. Nice! This is the SQL:

SELECT players.* FROM players 
  WHERE (players.position IN ('MF','FW')) 

Wrap Up

So, using all these examples, assuming you have this model:

class Post < ActiveRecord::Base
  extend ActsAsExplorable
  explorable in: [:title, :body],
             sort: [:title, :created_at],
             state: ['draft', 'published', 'trash']

  scope :older_than, -> (date) { where(%q{created_at <= ?}, date) }
end

You could query all posts in draft state with "Zlatan" in the title or body and sort the ascending by their creation date.

Zlatan in:title,body sort:created_at-asc state:draft

Post.search('Zlatan in:title,body sort:created_at-asc state:draft')

Now we have a SQL like this:

SELECT posts.* FROM posts 
  WHERE (posts.title ILIKE '%Zlatan%' OR posts.body ILIKE '%Zlatan%')
    AND (posts.state IN ('draft'))
  ORDER BY 
    posts.created_at ASC

You can also append your scopes:

Post.search('Zlatan in:title,body sort:created_at-asc state:draft').older_than(DateTime.now)

Testing

All tests follow the RSpec format and are located in the spec directory. They can be run with:

rake spec

License

Acts as explorable is released under the MIT License.

TODO

###v0.x

  • Add tests for postgres and mysql
  • Query string validation helper for use in forms
  • Use methods in addition to fields
  • Use named scopes