Skip to content
Provides a simplified DSL allowing arrays of objects to be searched by their attributes
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


queryable_array -

A QueryableArray inherits from Array and is intended to store a group of objects which share the same attributes allowing them to be searched. It overrides [], find_all and method_missing to provide a simplified DSL for looking up objects by querying their attributes.

View the full documentation over at


gem install queryable_array


Ruby 1.9+



Initialize the QueryableArray with a collection of objects e.g. Page objects from a JSON response or database query (although you should probably restrict database queries with WHERE conditions instead if you have the opportunity)

pages = Page.all

The pages object can then be queried by passing a search hash to the [] method

pages[uri: '/']                    # => #<Page @uri='/' @name='Home'>
pages[name: 'About']               # => #<Page @uri='/about' @name='About'>
pages[uri: '/', name: 'Home']      # => #<Page @uri='/' @name='Home'>
pages[uri: '/', name: 'Mismatch']  # => nil

Notice that it only returns the first matching object or nil if one is not found. If you'd like to find all matching objects, simply wrap your search hash in an array

pages[[published: true]]  # => [#<Page @uri='/' @name='Home' @published=true>, #<Page @uri='/about' @name='About' @published=true>, ...]
pages[[uri: '/missing']]  # => []

Attributes may also be searched by regular expressions

pages[name: /home/i]   # => #<Page @uri='/' @name='Home'>
pages[[uri: /users/]]  # => [#<Page @uri='/users/bob' @name='Bob'>, #<Page @uri='/users/steve' @name='Steve'>, ...]

The methods find_by and find_all behave as aliases for [search_hash] and [[search_hash]] respectively

pages.find_by(name: 'Home')     # => #<Page @uri='/' @name='Home'>
pages.find_by(name: 'Missing')  # => nil
pages.find_all(uri: /users/)    # => [#<Page @uri='/users/bob' @name='Bob'>, #<Page @uri='/users/steve' @name='Steve'>, ...]

The existing block form for those methods work as well

pages.find_all { |page| page.uri =~ /users/ }  # => [#<Page @uri='/users/bob' @name='Bob'>, #<Page @uri='/users/steve' @name='Steve'>, ...]

A Proc object may be passed to [] as well

pages[uri: proc { |uri| uri.split('/').size > 1 }]  # => #<Page @uri='/users/bob' @name='Bob'>
pages[proc { |page| page.uri == '/' }]              # => #<Page @uri='/' @name='Home'>

Lookups by index or ranges still behave exactly as they do in regular Array objects

pages[0]     # => #<Page @uri='/' @name='Home'>
pages[-1]    # => #<Page @uri='/zebras' @name='Zebras'>
pages[99]    # => nil
pages[0..1]  # => [#<Page @uri='/' @name='Home'>, #<Page @uri='/about' @name='About'>]

Default finders

A QueryableArray object can be initialized with a default_finder to make lookups even simpler

pages = Page.all, :uri

Now the pages object can be searched easily by uri

pages['/']         # => #<Page @uri='/' @name='Home'>
pages['/about']    # => #<Page @uri='/about' @name='About'>
pages['/missing']  # => nil

You can even specify multiple default_finders

pages = Page.all, [:uri, :name]

pages['/about']  # => #<Page @uri='/about' @name='About'>
pages['About']   # => #<Page @uri='/about' @name='About'>
pages[/home/i]   # => #<Page @uri='/' @name='Home'>

Wrapping your search inside an array still returns all matches

pages[[/users/]]  # => [#<Page @uri='/users/bob' @name='Bob'>, #<Page @uri='/users/steve' @name='Steve'>, ...]

Dynamic attribute-based finders

QueryableArray#method_missing allows you to lookup objects using a notation like the ActiveRecord dynamic finders

pages.find_by_uri('/')                   # => #<Page @uri='/' @name='Home'>
pages.find_by_uri_and_name('/', 'Home')  # => #<Page @uri='/' @name='Home'>
pages.find_by_uri('/missing')            # => nil

pages.find_all_by_uri('/')               # => [#<Page @uri='/' @name='Home'>]
pages.find_all_by_uri(/users/)           # => [#<Page @uri='/users/bob' @name='Bob'>, #<Page @uri='/users/steve' @name='Steve'>, ...]

Dot notation finders

If any default_finders are defined you may even use dot notation to lookup objects by those attributes

pages = Page.all, :name

pages.sitemap               # => #<Page @uri='/sitemap' @name='Sitemap'>
pages.missing               # => NoMethodError  # => NoMethodError

Calling pages.sitemap behaves the same as pages[/sitemap/i]

To perform a case-sensitive search, simply append a ! to the end of your method call e.g. pages.sitemap! which calls pages['sitemap']

You may also query to see if a match exists by appending a ? to your search

pages.sitemap?  # => true
pages.missing?  # => false


Functionality for QueryableArray has been separated out into individual modules containing their own features which allows you to create your own objects and only include the features you care about

  • QueryableArray::DefaultFinder - Allows objects to be searched by default_finders thru []

  • QueryableArray::DotNotation - Allows objects to be searched using dot notation thru method_missing which behaves like an alias to QueryableArray::DefaultFinder#[]

  • QueryableArray::DynamicFinder - Allows objects to be searched by dynamic finders thru method_missing similar to the ActiveRecord dynamic attribute-based finders e.g. find_by_email or find_all_by_last_name

  • QueryableArray::Queryable - Allows find_by and find_all to accept search hashes which are converted into Proc searches and passed as the block arguments for find and find_all respectively

  • QueryableArray::Shorthand - Makes [search_hash] and [[search_hash]] behave as an alias for find_by and find_all respectively

Try making your own classes with them

class Collection < Array
  include QueryableArray::Queryable

pages = Page.all
pages.find_all(published: true)  # => [#<Page @uri='/' @published=true>, #<Page @uri='/about' @published=true>]

Real world example

Try using it inside of your templates:

<div class="posts">
  <%- posts[[published: true]].each do |post| -%>
    <div class="post">
      <h2><a href="<%= post.url -%>"><%= post.title -%></a></h2>
      <div class="excerpt"><%= post.excerpt -%></div>
      <a href="<%= post.url -%>#comments"><%= post.comments[[approved: true]].size -%> comments</a>
  <%- end -%>


bundle exec rake
You can’t perform that action at this time.