A very basic gem for generating JSON responses for collections.
Currently supported:
- Pagination (via will_paginate)
- Simple Filters
Not supported:
- Combining multiple filters
- Filters with parameters
We use this gem in production, but it's uses are very specific to what we use. YMMV.
Add this line to your application's Gemfile:
gem 'filternator'
And then execute:
$ bundle
Or install it yourself as:
$ gem install filternator
Given a model:
class User < ActiveRecord::Base
def self.all_filters
%w(all paying beta_users)
end
def self.paying
where(paying: true)
end
def self.beta_users
where(beta: true)
end
def self.visible
where(visible: true)
end
end
Then you can create a filter in the controller:
def index
render json: filter.apply(params)
end
private
def filter
Filternator.new(scope: User.visible)
end
And you can execute it, like this:
get :index, filter: "all", "page" => 2
expect(response.body).to eq({
users: [
{
id: 31,
email: "[email protected]"
# etc...
}
],
meta: {
filters: ["all", "paying", "beta_users"],
applied_filter: "all",
pagination: {
total: 31,
total_pages: 2,
first_page: false,
last_page: true,
# and some more
}
}
}.to_json)
You can pass the pagination options directly into will_paginate's view helper.
<%= will_paginate OpenStruct.new(@user_response.body["meta"]["pagination"]) %>
(you should probably clean this up, but you get the point)
You can also generate an overview of the counts of each filter.
# in your controller
def stats
render json: filter.stats
end
Then the output looks something like this:
get :stats
expect(response.body).to eq({
all: 31,
paying: 4,
beta_users: 13,
}.to_json)
There are a bunch of ways to configure the filter.
Use a presenter to change the output of the collection, by giving something that can be mapped on each item.
UserDecorator = Struct.new(:user) do
def self.to_proc
method(:new).to_proc
end
def as_json(*)
{ name: user.name, email: user.email }
end
end
filter = Filternator.new(scope: User, presenter: UserDecorator)
By default, the name of the results is the plural of the model's name. You can
change it by providing the :scope_name
option.
filter = Filternator.new(scope: User.admins, scope_name: "administrators")
In the example mentioned above, I defined the list of available methods on the
class. You can also change the available filters per filterer, by supplying the
:all_filters
option.
# prohibits the access to the `paying`-scope.
filter = Filternator.new(scope: User, all_filters: %w(all beta_users))
Note for ActiveRecord 3: all
will not return a scope, but an array and will
not work. You use .scoped
instead. You can also override .all
to return
.scoped
, but that might break some of your code. If you choose a different
name than all
, you need to specify it, and allow it with all_filters
.
filter = Filternator.new(scope: User, default_filter: "scoped", all_filters: %w(scoped other))
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request