paraphrase
paraphrase provides a way to map one or multiple request params to model scopes.
paraphrase is geared towards building a query-based public API where you may want to require certain parameters to prevent consumers from scraping all your information or to mitigate large, performance-intensive database queries.
Installation
Via a gemfile:
gem 'paraphrase'
$ bundle
Or manually:
$ gem install paraphrase
Usage
Setup
paraphrase aims to be as flexible as possible. Query
classes can be created
in the following ways:
- Calling
register_mapping
in anActiveRecord::Base
subclass:
class Post < ActiveRecord::Base
register_mapping do
scope :by_user, :key => :author
end
def self.by_user()
joins(:user).where(:user => { :name => })
end
end
- A configuration block through
Paraphrase.configure
:
# config/initializers/paraphrase.rb
Paraphrase.configure do |mappings|
mappings.register :post do
paraphrases Post
scope :by_user, :key => :author
end
end
- Subclassing
Paraphrase::Query
:
class PostQuery < Paraphrase::Query
paraphrases Post
scope :by_user, :key => :author
end
Making a Query
In your controller, call the relevant method based on your setup:
class PostsController < ApplicationController
respond_to :html, :json
def index
@posts = Post.paraphrase(params)
# Or
# @posts = Paraphrase.query(:post, params)
# If you created a subclass
# @posts = PostQuery.new(params)
respond_with(@posts)
end
end
Configuring Scopes
In any of these contexts, the :key
option of the :scope
method registers
attribute(s) to extract from the params supplied and what method to pass them
to. An array of keys can be supplied to pass multiple arguments to a scope.
class Post < ActiveRecord::Base
register_mapping do
scope :by_user, :key => [:first_name, :last_name]
scope :published_on, :key => :pub_date
end
def self.by_user(first_name, last_name)
joins(:user).where(:user => { :first_name => first_name, :last_name => last_name })
end
def self.published_on(pub_date)
where(:published_on => pub_date)
end
end
If a scope is required for a query to be considered valid, pass :require =>
true
or :require => [:array, :of, :keys]
to the options. If any values are
missing for the scope, an empty result set will be returned. If a key is an
array of attributes, you can specify a subset of the key to be required. The
rest of the attributes will be allowed to be nil.
class Post < ActiveRecord::Base
register_mapping do
scope :published_on, :key => :pub_date, :require => true
scope :by_author, :key => [:first_name, :last_name], :require => :last_name # requires :last_name, whitelists :first_name
end
end
Post.paraphrase.results # => []
Alternatively, a scope can be whitelisted allowing nil values to be passed to the scope.
class Post < ActiveRecord::Base
register_mapping do
scope :by_author, :key => [:first_name, :last_name], :allow_nil => :first_name # :first_name does not need to be specified
end
end
Plans / Thoughts for the Future
- Support nested hashes in params.
scope :by_author, :key => { :author => [:first_name, :last_name] }