api_helper 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/.gitignore +1 -0
 - data/.travis.yml +6 -0
 - data/Appraisals +23 -0
 - data/README.md +7 -7
 - data/api_helper.gemspec +4 -0
 - data/examples/includable_childs.rabl +0 -0
 - data/gemfiles/grape_0.10.0.gemfile +8 -0
 - data/gemfiles/grape_0.11.0.gemfile +8 -0
 - data/gemfiles/rails_4.0.0.gemfile +8 -0
 - data/gemfiles/rails_4.1.0.gemfile +8 -0
 - data/gemfiles/rails_4.1.8.gemfile +8 -0
 - data/gemfiles/rails_4.2.0.gemfile +8 -0
 - data/lib/api_helper/fieldsettable.rb +141 -53
 - data/lib/api_helper/filterable.rb +66 -26
 - data/lib/api_helper/includable.rb +185 -60
 - data/lib/api_helper/version.rb +1 -1
 - metadata +67 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 326e1e9e2c1b9509990e1103a0d8f95da5be83a9
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 4c9fd145828a49a586d8a4b7dee67fa177ea957c
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: d14e69fb29488afe354b941fc4501ba92620936731673a2bc41274cf37f77bd4f2fbcf7e368e9dd8cc52e473a4b9b8ce1fd1b49391d59f6e638df0fac6452eda
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: f44a72e00cc934ad01194d0c20fa799f0fc6e232d26abced40f6a60b120b6942b66db0d3e21bfa90496ecc10e0b51b84833ad77727ebb2b85363dd1a5c7e5177
         
     | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/.travis.yml
    CHANGED
    
    
    
        data/Appraisals
    ADDED
    
    | 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            appraise 'rails-4.1.0' do
         
     | 
| 
      
 2 
     | 
    
         
            +
              gemspec
         
     | 
| 
      
 3 
     | 
    
         
            +
              gem 'rails', '4.1.0'
         
     | 
| 
      
 4 
     | 
    
         
            +
              gem 'rspec-rails'
         
     | 
| 
      
 5 
     | 
    
         
            +
            end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            appraise 'rails-4.2.0' do
         
     | 
| 
      
 8 
     | 
    
         
            +
              gemspec
         
     | 
| 
      
 9 
     | 
    
         
            +
              gem 'rails', '4.2.0'
         
     | 
| 
      
 10 
     | 
    
         
            +
              gem 'rspec-rails'
         
     | 
| 
      
 11 
     | 
    
         
            +
            end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            appraise 'grape-0.10.0' do
         
     | 
| 
      
 14 
     | 
    
         
            +
              gemspec
         
     | 
| 
      
 15 
     | 
    
         
            +
              gem 'grape', '0.10.0'
         
     | 
| 
      
 16 
     | 
    
         
            +
              gem 'rack-test'
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            appraise 'grape-0.11.0' do
         
     | 
| 
      
 20 
     | 
    
         
            +
              gemspec
         
     | 
| 
      
 21 
     | 
    
         
            +
              gem 'grape', '0.11.0'
         
     | 
| 
      
 22 
     | 
    
         
            +
              gem 'rack-test'
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,4 +1,4 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # APIHelper
         
     | 
| 
      
 1 
     | 
    
         
            +
            # APIHelper [](http://badge.fury.io/rb/api_helper) [](https://travis-ci.org/Neson/api_helper) [](https://inch-ci.org/github/Neson/api_helper)
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            Helpers for creating standard RESTful API for Rails or Grape with Active Record.
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
         @@ -8,7 +8,7 @@ Helpers for creating standard RESTful API for Rails or Grape with Active Record. 
     | 
|
| 
       8 
8 
     | 
    
         
             
            Add this line to your application's Gemfile:
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
            ```ruby
         
     | 
| 
       11 
     | 
    
         
            -
            gem ' 
     | 
| 
      
 11 
     | 
    
         
            +
            gem 'api_helper'
         
     | 
| 
       12 
12 
     | 
    
         
             
            ```
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
            And then execute:
         
     | 
| 
         @@ -17,7 +17,7 @@ And then execute: 
     | 
|
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
            Or install it yourself as:
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
                $ gem install  
     | 
| 
      
 20 
     | 
    
         
            +
                $ gem install api_helper
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
            ## API Standards
         
     | 
| 
         @@ -62,7 +62,7 @@ PostsController < ApplicationController 
     | 
|
| 
       62 
62 
     | 
    
         
             
            end
         
     | 
| 
       63 
63 
     | 
    
         
             
            ```
         
     | 
| 
       64 
64 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
            Further usage of each helper can be found in the docs.
         
     | 
| 
      
 65 
     | 
    
         
            +
            Further usage of each helper can be found in the [docs](http://www.rubydoc.info/github/Neson/api_helper/master/APIHelper).
         
     | 
| 
       66 
66 
     | 
    
         | 
| 
       67 
67 
     | 
    
         
             
            ### Grape
         
     | 
| 
       68 
68 
     | 
    
         | 
| 
         @@ -79,16 +79,16 @@ class PostsAPI < Grape::API 
     | 
|
| 
       79 
79 
     | 
    
         
             
            end
         
     | 
| 
       80 
80 
     | 
    
         
             
            ```
         
     | 
| 
       81 
81 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
            Further usage of each helper can be found in the docs.
         
     | 
| 
      
 82 
     | 
    
         
            +
            Further usage of each helper can be found in the [docs](http://www.rubydoc.info/github/Neson/api_helper/master/APIHelper).
         
     | 
| 
       83 
83 
     | 
    
         | 
| 
       84 
84 
     | 
    
         | 
| 
       85 
85 
     | 
    
         
             
            ## Development
         
     | 
| 
       86 
86 
     | 
    
         | 
| 
       87 
     | 
    
         
            -
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake  
     | 
| 
      
 87 
     | 
    
         
            +
            After checking out the repo, run `bin/setup` to install dependencies. Then, run `appraisal rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
         
     | 
| 
       88 
88 
     | 
    
         | 
| 
       89 
89 
     | 
    
         
             
            To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
         
     | 
| 
       90 
90 
     | 
    
         | 
| 
       91 
91 
     | 
    
         | 
| 
       92 
92 
     | 
    
         
             
            ## Contributing
         
     | 
| 
       93 
93 
     | 
    
         | 
| 
       94 
     | 
    
         
            -
            Bug reports and pull requests are welcome on GitHub at https://github.com/Neson/ 
     | 
| 
      
 94 
     | 
    
         
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/Neson/api_helper.
         
     | 
    
        data/api_helper.gemspec
    CHANGED
    
    | 
         @@ -20,7 +20,11 @@ Gem::Specification.new do |spec| 
     | 
|
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
              spec.add_development_dependency "bundler"
         
     | 
| 
       22 
22 
     | 
    
         
             
              spec.add_development_dependency "rake"
         
     | 
| 
      
 23 
     | 
    
         
            +
              spec.add_development_dependency "appraisal"
         
     | 
| 
       23 
24 
     | 
    
         
             
              spec.add_development_dependency "rspec"
         
     | 
| 
      
 25 
     | 
    
         
            +
              spec.add_development_dependency "byebug"
         
     | 
| 
      
 26 
     | 
    
         
            +
              spec.add_development_dependency "activerecord"
         
     | 
| 
      
 27 
     | 
    
         
            +
              spec.add_development_dependency "sqlite3"
         
     | 
| 
       24 
28 
     | 
    
         | 
| 
       25 
29 
     | 
    
         
             
              spec.add_dependency "activesupport", ">= 3"
         
     | 
| 
       26 
30 
     | 
    
         
             
            end
         
     | 
| 
         
            File without changes
         
     | 
| 
         @@ -1,31 +1,34 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'active_support'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'active_support/core_ext/object/blank'
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            # =  
     | 
| 
      
 4 
     | 
    
         
            +
            # = Fieldsettable
         
     | 
| 
       4 
5 
     | 
    
         
             
            #
         
     | 
| 
       5 
     | 
    
         
            -
            # By making an API fieldsettable, you  
     | 
| 
       6 
     | 
    
         
            -
            #  
     | 
| 
       7 
     | 
    
         
            -
            # API calls more efficient and 
     | 
| 
      
 6 
     | 
    
         
            +
            # By making an API fieldsettable, you enables the ability for API clients to
         
     | 
| 
      
 7 
     | 
    
         
            +
            # choose the returned fields of resources with URL query parameters. This is
         
     | 
| 
      
 8 
     | 
    
         
            +
            # really useful for optimizing requests, making API calls more efficient and
         
     | 
| 
      
 9 
     | 
    
         
            +
            # fast.
         
     | 
| 
       8 
10 
     | 
    
         
             
            #
         
     | 
| 
       9 
11 
     | 
    
         
             
            # This design made references to the rules of <em>Sparse Fieldsets</em> in
         
     | 
| 
       10 
12 
     | 
    
         
             
            # <em>JSON API</em>:
         
     | 
| 
       11 
13 
     | 
    
         
             
            # http://jsonapi.org/format/#fetching-sparse-fieldsets
         
     | 
| 
       12 
14 
     | 
    
         
             
            #
         
     | 
| 
       13 
     | 
    
         
            -
            # A client can request  
     | 
| 
       14 
     | 
    
         
            -
            #  
     | 
| 
       15 
     | 
    
         
            -
            #  
     | 
| 
      
 15 
     | 
    
         
            +
            # A client can request to get only specific fields in the response by using
         
     | 
| 
      
 16 
     | 
    
         
            +
            # the +fields+ parameter, which is expected to be a comma-separated (",") list
         
     | 
| 
      
 17 
     | 
    
         
            +
            # that refers to the name(s) of the fields to be returned.
         
     | 
| 
       16 
18 
     | 
    
         
             
            #
         
     | 
| 
       17 
19 
     | 
    
         
             
            #   GET /users?fields=id,name,avatar_url
         
     | 
| 
       18 
20 
     | 
    
         
             
            #
         
     | 
| 
       19 
     | 
    
         
            -
            # This functionality may also support requests  
     | 
| 
       20 
     | 
    
         
            -
            # for several  
     | 
| 
       21 
     | 
    
         
            -
            # another  
     | 
| 
      
 21 
     | 
    
         
            +
            # This functionality may also support requests passing in multiple fieldsets
         
     | 
| 
      
 22 
     | 
    
         
            +
            # for several resource at a time (e.g. an included related resource in an field
         
     | 
| 
      
 23 
     | 
    
         
            +
            # of another resource) with <tt>fields[object_type]</tt> parameters.
         
     | 
| 
       22 
24 
     | 
    
         
             
            #
         
     | 
| 
       23 
25 
     | 
    
         
             
            #   GET /posts?fields[posts]=id,title,author&fields[user]=id,name,avatar_url
         
     | 
| 
       24 
26 
     | 
    
         
             
            #
         
     | 
| 
       25 
27 
     | 
    
         
             
            # Note: +author+ of a +post+ is a +user+.
         
     | 
| 
       26 
28 
     | 
    
         
             
            #
         
     | 
| 
       27 
29 
     | 
    
         
             
            # The +fields+ and <tt>fields[object_type]</tt> parameters can not be mixed.
         
     | 
| 
       28 
     | 
    
         
            -
            # If the latter format is used, then it must be used for the main  
     | 
| 
      
 30 
     | 
    
         
            +
            # If the latter format is used, then it must be used for the main resource as
         
     | 
| 
      
 31 
     | 
    
         
            +
            # well.
         
     | 
| 
       29 
32 
     | 
    
         
             
            #
         
     | 
| 
       30 
33 
     | 
    
         
             
            # == Usage
         
     | 
| 
       31 
34 
     | 
    
         
             
            #
         
     | 
| 
         @@ -38,26 +41,35 @@ require 'active_support' 
     | 
|
| 
       38 
41 
     | 
    
         
             
            # or in your Grape API class:
         
     | 
| 
       39 
42 
     | 
    
         
             
            #
         
     | 
| 
       40 
43 
     | 
    
         
             
            #   class SampleAPI < Grape::API
         
     | 
| 
       41 
     | 
    
         
            -
            #      
     | 
| 
      
 44 
     | 
    
         
            +
            #     helpers APIHelper::Fieldsettable
         
     | 
| 
       42 
45 
     | 
    
         
             
            #   end
         
     | 
| 
       43 
46 
     | 
    
         
             
            #
         
     | 
| 
       44 
     | 
    
         
            -
            #  
     | 
| 
      
 47 
     | 
    
         
            +
            # Then set fieldset with +fieldset_for+ for each resource in the controller:
         
     | 
| 
      
 48 
     | 
    
         
            +
            #
         
     | 
| 
      
 49 
     | 
    
         
            +
            #   def index
         
     | 
| 
      
 50 
     | 
    
         
            +
            #     fieldset_for :post, default: true, default_fields: [:id, :title, :author]
         
     | 
| 
      
 51 
     | 
    
         
            +
            #     fieldset_for :user, permitted_fields: [:id, :name, :posts, :avatar_url],
         
     | 
| 
      
 52 
     | 
    
         
            +
            #                         defaults_to_permitted_fields: true
         
     | 
| 
      
 53 
     | 
    
         
            +
            #     # ...
         
     | 
| 
      
 54 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 55 
     | 
    
         
            +
            #
         
     | 
| 
      
 56 
     | 
    
         
            +
            # or in the Grape method if you're using Grape:
         
     | 
| 
       45 
57 
     | 
    
         
             
            #
         
     | 
| 
       46 
58 
     | 
    
         
             
            #   resources :posts do
         
     | 
| 
       47 
59 
     | 
    
         
             
            #     get do
         
     | 
| 
       48 
     | 
    
         
            -
            #       fieldset_for :post,  
     | 
| 
      
 60 
     | 
    
         
            +
            #       fieldset_for :post, default: true, default_fields: [:id, :title, :author]
         
     | 
| 
       49 
61 
     | 
    
         
             
            #       fieldset_for :user, permitted_fields: [:id, :name, :posts, :avatar_url],
         
     | 
| 
       50 
     | 
    
         
            -
            #                            
     | 
| 
      
 62 
     | 
    
         
            +
            #                           defaults_to_permitted_fields: true
         
     | 
| 
       51 
63 
     | 
    
         
             
            #       # ...
         
     | 
| 
       52 
64 
     | 
    
         
             
            #     end
         
     | 
| 
       53 
65 
     | 
    
         
             
            #   end
         
     | 
| 
       54 
66 
     | 
    
         
             
            #
         
     | 
| 
       55 
     | 
    
         
            -
            #  
     | 
| 
       56 
     | 
    
         
            -
            #  
     | 
| 
       57 
     | 
    
         
            -
            #  
     | 
| 
      
 67 
     | 
    
         
            +
            # The +fieldset_for+ method used above parses the +fields+ and/or
         
     | 
| 
      
 68 
     | 
    
         
            +
            # <tt>fields[resource_name]</tt> parameters, and save the results into
         
     | 
| 
      
 69 
     | 
    
         
            +
            # +@fieldset+ instance variable for further usage.
         
     | 
| 
       58 
70 
     | 
    
         
             
            #
         
     | 
| 
       59 
     | 
    
         
            -
            # After  
     | 
| 
       60 
     | 
    
         
            -
            #  
     | 
| 
      
 71 
     | 
    
         
            +
            # After that line, you can use the +fieldset+ helper method to get the fieldset
         
     | 
| 
      
 72 
     | 
    
         
            +
            # information. Actual examples are:
         
     | 
| 
       61 
73 
     | 
    
         
             
            #
         
     | 
| 
       62 
74 
     | 
    
         
             
            # With <tt>GET /posts?fields=title,author</tt>:
         
     | 
| 
       63 
75 
     | 
    
         
             
            #
         
     | 
| 
         @@ -70,26 +82,53 @@ require 'active_support' 
     | 
|
| 
       70 
82 
     | 
    
         
             
            #   fieldset(:post, :title) #=> true
         
     | 
| 
       71 
83 
     | 
    
         
             
            #   fieldset(:user, :avatar_url) #=> false
         
     | 
| 
       72 
84 
     | 
    
         
             
            #
         
     | 
| 
       73 
     | 
    
         
            -
            # You can make use of  
     | 
| 
      
 85 
     | 
    
         
            +
            # You can make use of these information while dealing with requests in the
         
     | 
| 
      
 86 
     | 
    
         
            +
            # controller, for example:
         
     | 
| 
      
 87 
     | 
    
         
            +
            #
         
     | 
| 
      
 88 
     | 
    
         
            +
            #   Post.select(fieldset(:post)).find(params[:id])
         
     | 
| 
      
 89 
     | 
    
         
            +
            #
         
     | 
| 
      
 90 
     | 
    
         
            +
            # And return only specified fields in the view, for instance, Jbuilder:
         
     | 
| 
      
 91 
     | 
    
         
            +
            #
         
     | 
| 
      
 92 
     | 
    
         
            +
            #   json.(@post, *fieldset(:post))
         
     | 
| 
      
 93 
     | 
    
         
            +
            #   json.author do
         
     | 
| 
      
 94 
     | 
    
         
            +
            #     json.(@author, *fieldset(:user))
         
     | 
| 
      
 95 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 96 
     | 
    
         
            +
            #
         
     | 
| 
      
 97 
     | 
    
         
            +
            # or RABL:
         
     | 
| 
      
 98 
     | 
    
         
            +
            #
         
     | 
| 
      
 99 
     | 
    
         
            +
            #   # post.rabl
         
     | 
| 
       74 
100 
     | 
    
         
             
            #
         
     | 
| 
       75 
     | 
    
         
            -
            #    
     | 
| 
      
 101 
     | 
    
         
            +
            #   object @post
         
     | 
| 
      
 102 
     | 
    
         
            +
            #   attributes(*fieldset[:post])
         
     | 
| 
      
 103 
     | 
    
         
            +
            #   child :author do
         
     | 
| 
      
 104 
     | 
    
         
            +
            #     extends 'user'
         
     | 
| 
      
 105 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 106 
     | 
    
         
            +
            #
         
     | 
| 
      
 107 
     | 
    
         
            +
            #   # user.rabl
         
     | 
| 
      
 108 
     | 
    
         
            +
            #
         
     | 
| 
      
 109 
     | 
    
         
            +
            #   object @user
         
     | 
| 
      
 110 
     | 
    
         
            +
            #   attributes(*fieldset[:user])
         
     | 
| 
       76 
111 
     | 
    
         
             
            #
         
     | 
| 
       77 
     | 
    
         
            -
            #  
     | 
| 
      
 112 
     | 
    
         
            +
            # You can also set properties of fieldset with the +set_fieldset+ helper method
         
     | 
| 
      
 113 
     | 
    
         
            +
            # in the views if you're using a same view across multiple controllers, for
         
     | 
| 
      
 114 
     | 
    
         
            +
            # decreasing code duplication or increasing security. Below is an example with
         
     | 
| 
      
 115 
     | 
    
         
            +
            # RABL:
         
     | 
| 
       78 
116 
     | 
    
         
             
            #
         
     | 
| 
       79 
117 
     | 
    
         
             
            #   object @user
         
     | 
| 
       80 
118 
     | 
    
         
             
            #
         
     | 
| 
       81 
     | 
    
         
            -
            #   # this ensures the +fieldset+ instance variable is least setted with
         
     | 
| 
       82 
     | 
    
         
            -
            #   # the default fields, and double  
     | 
| 
       83 
     | 
    
         
            -
            #   # in case of things going wrong in the controller
         
     | 
| 
      
 119 
     | 
    
         
            +
            #   # this ensures that the +fieldset+ instance variable is least setted with
         
     | 
| 
      
 120 
     | 
    
         
            +
            #   # the default fields, and double filters +permitted_fields+ at view layer -
         
     | 
| 
      
 121 
     | 
    
         
            +
            #   # in case of any things going wrong in the controller
         
     | 
| 
       84 
122 
     | 
    
         
             
            #   set_fieldset :user, default_fields: [:id, :name, :avatar_url],
         
     | 
| 
       85 
123 
     | 
    
         
             
            #                       permitted_fields: [:id, :name, :avatar_url, :posts]
         
     | 
| 
       86 
124 
     | 
    
         
             
            #
         
     | 
| 
       87 
125 
     | 
    
         
             
            #   # determine the fields to show on the fly
         
     | 
| 
       88 
126 
     | 
    
         
             
            #   attributes(*fieldset[:user])
         
     | 
| 
      
 127 
     | 
    
         
            +
            #
         
     | 
| 
       89 
128 
     | 
    
         
             
            module APIHelper::Fieldsettable
         
     | 
| 
       90 
129 
     | 
    
         
             
              extend ActiveSupport::Concern
         
     | 
| 
       91 
130 
     | 
    
         | 
| 
       92 
     | 
    
         
            -
              # Gets the fields parameters, organize them into a +@fieldset+ hash for model to select certain
         
     | 
| 
      
 131 
     | 
    
         
            +
              # Gets the fields parameters, organize them into a +@fieldset+ hash for model to select certain.
         
     | 
| 
       93 
132 
     | 
    
         
             
              # fields and/or templates to render specified fieldset. Following the URL rules of JSON API:
         
     | 
| 
       94 
133 
     | 
    
         
             
              # http://jsonapi.org/format/#fetching-sparse-fieldsets
         
     | 
| 
       95 
134 
     | 
    
         
             
              #
         
     | 
| 
         @@ -98,8 +137,9 @@ module APIHelper::Fieldsettable 
     | 
|
| 
       98 
137 
     | 
    
         
             
              # +resource+::
         
     | 
| 
       99 
138 
     | 
    
         
             
              #   +Symbol+ name of resource to receive the fieldset
         
     | 
| 
       100 
139 
     | 
    
         
             
              #
         
     | 
| 
       101 
     | 
    
         
            -
              # + 
     | 
| 
       102 
     | 
    
         
            -
              #   +Boolean+ should this resource take the parameter from +fields+ while no 
     | 
| 
      
 140 
     | 
    
         
            +
              # +default+::
         
     | 
| 
      
 141 
     | 
    
         
            +
              #   +Boolean+ should this resource take the parameter from +fields+ while no
         
     | 
| 
      
 142 
     | 
    
         
            +
              #             resourse name is specified?
         
     | 
| 
       103 
143 
     | 
    
         
             
              #
         
     | 
| 
       104 
144 
     | 
    
         
             
              # +permitted_fields+::
         
     | 
| 
       105 
145 
     | 
    
         
             
              #   +Array+ of +Symbol+s list of accessible fields used to filter out unpermitted fields,
         
     | 
| 
         @@ -108,9 +148,9 @@ module APIHelper::Fieldsettable 
     | 
|
| 
       108 
148 
     | 
    
         
             
              # +default_fields+::
         
     | 
| 
       109 
149 
     | 
    
         
             
              #   +Array+ of +Symbol+s list of fields to show by default
         
     | 
| 
       110 
150 
     | 
    
         
             
              #
         
     | 
| 
       111 
     | 
    
         
            -
              # + 
     | 
| 
       112 
     | 
    
         
            -
              #   +Boolean+ if set to true, @fieldset will be set to all permitted_fields 
     | 
| 
       113 
     | 
    
         
            -
              #   resource's fieldset isn't specified
         
     | 
| 
      
 151 
     | 
    
         
            +
              # +defaults_to_permitted_fields+::
         
     | 
| 
      
 152 
     | 
    
         
            +
              #   +Boolean+ if set to true, @fieldset will be set to all permitted_fields
         
     | 
| 
      
 153 
     | 
    
         
            +
              #   when the current resource's fieldset isn't specified
         
     | 
| 
       114 
154 
     | 
    
         
             
              #
         
     | 
| 
       115 
155 
     | 
    
         
             
              # Example Result:
         
     | 
| 
       116 
156 
     | 
    
         
             
              #
         
     | 
| 
         @@ -121,46 +161,88 @@ module APIHelper::Fieldsettable 
     | 
|
| 
       121 
161 
     | 
    
         
             
              #     #                :user => [:id, :name, :email, :groups],
         
     | 
| 
       122 
162 
     | 
    
         
             
              #     #                :group => [:id, :name]
         
     | 
| 
       123 
163 
     | 
    
         
             
              #     #              }
         
     | 
| 
       124 
     | 
    
         
            -
               
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
      
 164 
     | 
    
         
            +
              #
         
     | 
| 
      
 165 
     | 
    
         
            +
              def fieldset_for(resource, default: false,
         
     | 
| 
      
 166 
     | 
    
         
            +
                                         permitted_fields: [],
         
     | 
| 
      
 167 
     | 
    
         
            +
                                         defaults_to_permitted_fields: false,
         
     | 
| 
      
 168 
     | 
    
         
            +
                                         default_fields: [])
         
     | 
| 
      
 169 
     | 
    
         
            +
                @fieldset ||= ActiveSupport::HashWithIndifferentAccess.new
         
     | 
| 
       127 
170 
     | 
    
         | 
| 
       128 
171 
     | 
    
         
             
                # put the fields in place
         
     | 
| 
       129 
     | 
    
         
            -
                if params[:fields].is_a? 
     | 
| 
      
 172 
     | 
    
         
            +
                if params[:fields].is_a?(Hash)
         
     | 
| 
      
 173 
     | 
    
         
            +
                  # get the specific resource fields from fields hash
         
     | 
| 
       130 
174 
     | 
    
         
             
                  @fieldset[resource] = params[:fields][resource] || params[:fields][resource]
         
     | 
| 
       131 
     | 
    
         
            -
                elsif  
     | 
| 
      
 175 
     | 
    
         
            +
                elsif default
         
     | 
| 
      
 176 
     | 
    
         
            +
                  # or get the fields string directly if this resource is th default one
         
     | 
| 
       132 
177 
     | 
    
         
             
                  @fieldset[resource] = params[:fields]
         
     | 
| 
       133 
178 
     | 
    
         
             
                end
         
     | 
| 
       134 
179 
     | 
    
         | 
| 
       135 
     | 
    
         
            -
                # splits the string into array 
     | 
| 
       136 
     | 
    
         
            -
                 
     | 
| 
      
 180 
     | 
    
         
            +
                # splits the string into array
         
     | 
| 
      
 181 
     | 
    
         
            +
                if @fieldset[resource].present?
         
     | 
| 
      
 182 
     | 
    
         
            +
                  @fieldset[resource] = @fieldset[resource].split(',').map(&:to_s)
         
     | 
| 
      
 183 
     | 
    
         
            +
                else
         
     | 
| 
      
 184 
     | 
    
         
            +
                  @fieldset[resource] = default_fields.map(&:to_s)
         
     | 
| 
      
 185 
     | 
    
         
            +
                end
         
     | 
| 
       137 
186 
     | 
    
         | 
| 
       138 
     | 
    
         
            -
                 
     | 
| 
       139 
     | 
    
         
            -
             
     | 
| 
      
 187 
     | 
    
         
            +
                if permitted_fields.present?
         
     | 
| 
      
 188 
     | 
    
         
            +
                  permitted_fields = permitted_fields.map(&:to_s)
         
     | 
| 
       140 
189 
     | 
    
         | 
| 
       141 
     | 
    
         
            -
             
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
              end
         
     | 
| 
      
 190 
     | 
    
         
            +
                  # filter out unpermitted fields by intersecting them
         
     | 
| 
      
 191 
     | 
    
         
            +
                  @fieldset[resource] &= permitted_fields if @fieldset[resource].present?
         
     | 
| 
       144 
192 
     | 
    
         | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
             
     | 
| 
       148 
     | 
    
         
            -
                 
     | 
| 
       149 
     | 
    
         
            -
                @fieldset[resource] &= permitted_fields
         
     | 
| 
      
 193 
     | 
    
         
            +
                  # set default fields to permitted_fields if needed
         
     | 
| 
      
 194 
     | 
    
         
            +
                  @fieldset[resource] = permitted_fields if @fieldset[resource].blank? &&
         
     | 
| 
      
 195 
     | 
    
         
            +
                                                            defaults_to_permitted_fields
         
     | 
| 
      
 196 
     | 
    
         
            +
                end
         
     | 
| 
       150 
197 
     | 
    
         
             
              end
         
     | 
| 
       151 
198 
     | 
    
         | 
| 
       152 
199 
     | 
    
         
             
              # Getter for the fieldset data
         
     | 
| 
      
 200 
     | 
    
         
            +
              #
         
     | 
| 
      
 201 
     | 
    
         
            +
              # This method will act as a traditional getter of the fieldset data and
         
     | 
| 
      
 202 
     | 
    
         
            +
              # returns a hash containing fields for each resource if no parameter is
         
     | 
| 
      
 203 
     | 
    
         
            +
              # provided.
         
     | 
| 
      
 204 
     | 
    
         
            +
              #
         
     | 
| 
      
 205 
     | 
    
         
            +
              #   fieldset  # => { 'user' => ['name'], 'post' => ['title', 'author'] }
         
     | 
| 
      
 206 
     | 
    
         
            +
              #
         
     | 
| 
      
 207 
     | 
    
         
            +
              # If one parameter - a specific resourse name is passed in, it will return
         
     | 
| 
      
 208 
     | 
    
         
            +
              # a fields array of that specific resourse.
         
     | 
| 
      
 209 
     | 
    
         
            +
              #
         
     | 
| 
      
 210 
     | 
    
         
            +
              #   fieldset(:post)  # => ['title', 'author']
         
     | 
| 
      
 211 
     | 
    
         
            +
              #
         
     | 
| 
      
 212 
     | 
    
         
            +
              # And if one more parameter - a field name, is passed in, it will return a
         
     | 
| 
      
 213 
     | 
    
         
            +
              # boolen, determining if that field should exist in that resource.
         
     | 
| 
      
 214 
     | 
    
         
            +
              #
         
     | 
| 
      
 215 
     | 
    
         
            +
              #   fieldset(:post, :title)  # => true
         
     | 
| 
      
 216 
     | 
    
         
            +
              #
         
     | 
| 
       153 
217 
     | 
    
         
             
              def fieldset(resource = nil, field = nil)
         
     | 
| 
      
 218 
     | 
    
         
            +
                # act as a traditional getter if no parameters specified
         
     | 
| 
       154 
219 
     | 
    
         
             
                if resource.blank?
         
     | 
| 
       155 
     | 
    
         
            -
                  @fieldset ||=  
     | 
| 
      
 220 
     | 
    
         
            +
                  @fieldset ||= ActiveSupport::HashWithIndifferentAccess.new
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
                # returns the fieldset array if an specific resource is passed in
         
     | 
| 
       156 
223 
     | 
    
         
             
                elsif field.blank?
         
     | 
| 
       157 
     | 
    
         
            -
                   
     | 
| 
      
 224 
     | 
    
         
            +
                  fieldset[resource] || []
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                # determine if a field is inculded in a specific fieldset
         
     | 
| 
       158 
227 
     | 
    
         
             
                else
         
     | 
| 
       159 
     | 
    
         
            -
                   
     | 
| 
      
 228 
     | 
    
         
            +
                  field = field.to_s
         
     | 
| 
      
 229 
     | 
    
         
            +
                  fieldset(resource).is_a?(Array) && fieldset(resource).include?(field)
         
     | 
| 
       160 
230 
     | 
    
         
             
                end
         
     | 
| 
       161 
231 
     | 
    
         
             
              end
         
     | 
| 
       162 
232 
     | 
    
         | 
| 
       163 
     | 
    
         
            -
              #  
     | 
| 
      
 233 
     | 
    
         
            +
              # View Helper to set the default and permitted fields
         
     | 
| 
      
 234 
     | 
    
         
            +
              #
         
     | 
| 
      
 235 
     | 
    
         
            +
              # This is useful while using an resource view shared by multiple controllers,
         
     | 
| 
      
 236 
     | 
    
         
            +
              # it will ensure the +@fieldset+ instance variable presents, and can also set
         
     | 
| 
      
 237 
     | 
    
         
            +
              # the default fields of a model for convenience, or the whitelisted permitted
         
     | 
| 
      
 238 
     | 
    
         
            +
              # fields for security.
         
     | 
| 
      
 239 
     | 
    
         
            +
              def set_fieldset(resource, default_fields: [], permitted_fields: [])
         
     | 
| 
      
 240 
     | 
    
         
            +
                @fieldset ||= ActiveSupport::HashWithIndifferentAccess.new
         
     | 
| 
      
 241 
     | 
    
         
            +
                @fieldset[resource] = default_fields.map(&:to_s) if @fieldset[resource].blank?
         
     | 
| 
      
 242 
     | 
    
         
            +
                @fieldset[resource] &= permitted_fields.map(&:to_s) if permitted_fields.present?
         
     | 
| 
      
 243 
     | 
    
         
            +
              end
         
     | 
| 
      
 244 
     | 
    
         
            +
             
     | 
| 
      
 245 
     | 
    
         
            +
              # Returns the description of the 'fields' URL parameter
         
     | 
| 
       164 
246 
     | 
    
         
             
              def self.fields_param_desc(example: nil)
         
     | 
| 
       165 
247 
     | 
    
         
             
                if example.present?
         
     | 
| 
       166 
248 
     | 
    
         
             
                  "Choose the fields to be returned. Example value: '#{example}'"
         
     | 
| 
         @@ -168,4 +250,10 @@ module APIHelper::Fieldsettable 
     | 
|
| 
       168 
250 
     | 
    
         
             
                  "Choose the fields to be returned."
         
     | 
| 
       169 
251 
     | 
    
         
             
                end
         
     | 
| 
       170 
252 
     | 
    
         
             
              end
         
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
              included do
         
     | 
| 
      
 255 
     | 
    
         
            +
                if defined? helper_method
         
     | 
| 
      
 256 
     | 
    
         
            +
                  helper_method :fieldset, :set_fieldset
         
     | 
| 
      
 257 
     | 
    
         
            +
                end
         
     | 
| 
      
 258 
     | 
    
         
            +
              end
         
     | 
| 
       171 
259 
     | 
    
         
             
            end
         
     | 
| 
         @@ -1,9 +1,10 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'active_support'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'active_support/core_ext/object/blank'
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            # =  
     | 
| 
      
 4 
     | 
    
         
            +
            # = Filterable
         
     | 
| 
       4 
5 
     | 
    
         
             
            #
         
     | 
| 
       5 
     | 
    
         
            -
            # A filterable resource API supports requests to filter resources  
     | 
| 
       6 
     | 
    
         
            -
            #  
     | 
| 
      
 6 
     | 
    
         
            +
            # A filterable resource API supports requests to filter resources in collection
         
     | 
| 
      
 7 
     | 
    
         
            +
            # by their fields, using the +filter+ query parameter.
         
     | 
| 
       7 
8 
     | 
    
         
             
            #
         
     | 
| 
       8 
9 
     | 
    
         
             
            # For example, the following is a request for all products that has a
         
     | 
| 
       9 
10 
     | 
    
         
             
            # particular color:
         
     | 
| 
         @@ -16,19 +17,23 @@ require 'active_support' 
     | 
|
| 
       16 
17 
     | 
    
         
             
            #
         
     | 
| 
       17 
18 
     | 
    
         
             
            # <em>Multiple filters are applied with the AND condition.</em>
         
     | 
| 
       18 
19 
     | 
    
         
             
            #
         
     | 
| 
       19 
     | 
    
         
            -
            #  
     | 
| 
      
 20 
     | 
    
         
            +
            # A list separated by commas (",") can be used to filter by field matching one
         
     | 
| 
      
 21 
     | 
    
         
            +
            # of the values:
         
     | 
| 
       20 
22 
     | 
    
         
             
            #
         
     | 
| 
       21 
23 
     | 
    
         
             
            #   GET /products?filter[color]=red,blue,yellow
         
     | 
| 
       22 
24 
     | 
    
         
             
            #
         
     | 
| 
       23 
25 
     | 
    
         
             
            # A few functions: +not+, +greater_then+, +less_then+, +greater_then_or_equal+,
         
     | 
| 
       24 
     | 
    
         
            -
            # +less_then_or_equal+, +between+ and + 
     | 
| 
       25 
     | 
    
         
            -
            # the data, for example:
         
     | 
| 
      
 26 
     | 
    
         
            +
            # +less_then_or_equal+, +between+, +like+, +contains+, +null+ and +blank+ can
         
     | 
| 
      
 27 
     | 
    
         
            +
            # be used to filter the data, for example:
         
     | 
| 
       26 
28 
     | 
    
         
             
            #
         
     | 
| 
       27 
29 
     | 
    
         
             
            #   GET /products?filter[color]=not(red)
         
     | 
| 
       28 
30 
     | 
    
         
             
            #   GET /products?filter[price]=greater_then(1000)
         
     | 
| 
       29 
31 
     | 
    
         
             
            #   GET /products?filter[price]=less_then_or_equal(2000)
         
     | 
| 
       30 
32 
     | 
    
         
             
            #   GET /products?filter[price]=between(1000,2000)
         
     | 
| 
       31 
33 
     | 
    
         
             
            #   GET /products?filter[name]=like(%lovely%)
         
     | 
| 
      
 34 
     | 
    
         
            +
            #   GET /products?filter[name]=contains(%lovely%)
         
     | 
| 
      
 35 
     | 
    
         
            +
            #   GET /products?filter[provider]=null()
         
     | 
| 
      
 36 
     | 
    
         
            +
            #   GET /products?filter[provider]=blank()
         
     | 
| 
       32 
37 
     | 
    
         
             
            #
         
     | 
| 
       33 
38 
     | 
    
         
             
            # == Usage
         
     | 
| 
       34 
39 
     | 
    
         
             
            #
         
     | 
| 
         @@ -41,20 +46,16 @@ require 'active_support' 
     | 
|
| 
       41 
46 
     | 
    
         
             
            # or in your Grape API class:
         
     | 
| 
       42 
47 
     | 
    
         
             
            #
         
     | 
| 
       43 
48 
     | 
    
         
             
            #   class SampleAPI < Grape::API
         
     | 
| 
       44 
     | 
    
         
            -
            #      
     | 
| 
      
 49 
     | 
    
         
            +
            #     helpers APIHelper::Filterable
         
     | 
| 
       45 
50 
     | 
    
         
             
            #   end
         
     | 
| 
       46 
51 
     | 
    
         
             
            #
         
     | 
| 
       47 
     | 
    
         
            -
            # then use the +filter+ method like this:
         
     | 
| 
      
 52 
     | 
    
         
            +
            # then use the +filter+ method in the controller like this:
         
     | 
| 
       48 
53 
     | 
    
         
             
            #
         
     | 
| 
       49 
     | 
    
         
            -
            #    
     | 
| 
       50 
     | 
    
         
            -
            # 
     | 
| 
       51 
     | 
    
         
            -
            # 
     | 
| 
       52 
     | 
    
         
            -
            # 
     | 
| 
       53 
     | 
    
         
            -
            #     end
         
     | 
| 
       54 
     | 
    
         
            -
            #   end
         
     | 
| 
      
 54 
     | 
    
         
            +
            #   @products = filter(Post, filterable_fields: [:name, :price, :color])
         
     | 
| 
      
 55 
     | 
    
         
            +
            #
         
     | 
| 
      
 56 
     | 
    
         
            +
            # <em>The +filter+ method will return a scoped model collection, based
         
     | 
| 
      
 57 
     | 
    
         
            +
            # directly from the requested URL parameters.</em>
         
     | 
| 
       55 
58 
     | 
    
         
             
            #
         
     | 
| 
       56 
     | 
    
         
            -
            # <em>The +filter+ method will return the scoped model, based directly
         
     | 
| 
       57 
     | 
    
         
            -
            # from the requested URL.</em>
         
     | 
| 
       58 
59 
     | 
    
         
             
            module APIHelper::Filterable
         
     | 
| 
       59 
60 
     | 
    
         
             
              extend ActiveSupport::Concern
         
     | 
| 
       60 
61 
     | 
    
         | 
| 
         @@ -63,20 +64,25 @@ module APIHelper::Filterable 
     | 
|
| 
       63 
64 
     | 
    
         
             
              # Params:
         
     | 
| 
       64 
65 
     | 
    
         
             
              #
         
     | 
| 
       65 
66 
     | 
    
         
             
              # +resource+::
         
     | 
| 
       66 
     | 
    
         
            -
              #   +ActiveRecord:: 
     | 
| 
      
 67 
     | 
    
         
            +
              #   +ActiveRecord::Relation+ resource collection
         
     | 
| 
       67 
68 
     | 
    
         
             
              #   to filter data from
         
     | 
| 
       68 
69 
     | 
    
         
             
              #
         
     | 
| 
       69 
70 
     | 
    
         
             
              # +filterable_fields+::
         
     | 
| 
       70 
     | 
    
         
            -
              #   +Array+ of +Symbol+s fields that are allowed to be filtered,  
     | 
| 
      
 71 
     | 
    
         
            +
              #   +Array+ of +Symbol+s fields that are allowed to be filtered, defaults
         
     | 
| 
       71 
72 
     | 
    
         
             
              #   to all
         
     | 
| 
      
 73 
     | 
    
         
            +
              #
         
     | 
| 
       72 
74 
     | 
    
         
             
              def filter(resource, filterable_fields: [])
         
     | 
| 
       73 
75 
     | 
    
         
             
                # parse the request parameter
         
     | 
| 
       74 
     | 
    
         
            -
                if params[:filter].is_a? 
     | 
| 
      
 76 
     | 
    
         
            +
                if params[:filter].is_a?(Hash)
         
     | 
| 
       75 
77 
     | 
    
         
             
                  @filter = params[:filter]
         
     | 
| 
       76 
78 
     | 
    
         
             
                  filterable_fields = filterable_fields.map(&:to_s)
         
     | 
| 
       77 
79 
     | 
    
         | 
| 
      
 80 
     | 
    
         
            +
                  # deal with each condition
         
     | 
| 
       78 
81 
     | 
    
         
             
                  @filter.each_pair do |field, condition|
         
     | 
| 
      
 82 
     | 
    
         
            +
                    # bypass fields that aren't be abled to filter with
         
     | 
| 
       79 
83 
     | 
    
         
             
                    next if filterable_fields.present? && !filterable_fields.include?(field)
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    # escape string to prevent SQL injection
         
     | 
| 
       80 
86 
     | 
    
         
             
                    field = resource.connection.quote_string(field)
         
     | 
| 
       81 
87 
     | 
    
         | 
| 
       82 
88 
     | 
    
         
             
                    next if resource.columns_hash[field].blank?
         
     | 
| 
         @@ -89,22 +95,50 @@ module APIHelper::Filterable 
     | 
|
| 
       89 
95 
     | 
    
         
             
                        values = func[:param].split(',')
         
     | 
| 
       90 
96 
     | 
    
         
             
                        values.map!(&:to_bool) if field_type == :boolean
         
     | 
| 
       91 
97 
     | 
    
         
             
                        resource = resource.where.not(field => values)
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
       92 
99 
     | 
    
         
             
                      when 'greater_then'
         
     | 
| 
       93 
     | 
    
         
            -
                        resource = resource 
     | 
| 
      
 100 
     | 
    
         
            +
                        resource = resource
         
     | 
| 
      
 101 
     | 
    
         
            +
                                   .where("\"#{resource.table_name}\".\"#{field}\" > ?",
         
     | 
| 
      
 102 
     | 
    
         
            +
                                          func[:param])
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
       94 
104 
     | 
    
         
             
                      when 'less_then'
         
     | 
| 
       95 
     | 
    
         
            -
                        resource = resource 
     | 
| 
      
 105 
     | 
    
         
            +
                        resource = resource
         
     | 
| 
      
 106 
     | 
    
         
            +
                                   .where("\"#{resource.table_name}\".\"#{field}\" < ?",
         
     | 
| 
      
 107 
     | 
    
         
            +
                                          func[:param])
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
       96 
109 
     | 
    
         
             
                      when 'greater_then_or_equal'
         
     | 
| 
       97 
     | 
    
         
            -
                        resource = resource 
     | 
| 
      
 110 
     | 
    
         
            +
                        resource = resource
         
     | 
| 
      
 111 
     | 
    
         
            +
                                   .where("\"#{resource.table_name}\".\"#{field}\" >= ?",
         
     | 
| 
      
 112 
     | 
    
         
            +
                                          func[:param])
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
       98 
114 
     | 
    
         
             
                      when 'less_then_or_equal'
         
     | 
| 
       99 
     | 
    
         
            -
                        resource = resource 
     | 
| 
      
 115 
     | 
    
         
            +
                        resource = resource
         
     | 
| 
      
 116 
     | 
    
         
            +
                                   .where("\"#{resource.table_name}\".\"#{field}\" <= ?",
         
     | 
| 
      
 117 
     | 
    
         
            +
                                          func[:param])
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
       100 
119 
     | 
    
         
             
                      when 'between'
         
     | 
| 
       101 
120 
     | 
    
         
             
                        param = func[:param].split(',')
         
     | 
| 
       102 
     | 
    
         
            -
                        resource = resource 
     | 
| 
      
 121 
     | 
    
         
            +
                        resource = resource
         
     | 
| 
      
 122 
     | 
    
         
            +
                                   .where("\"#{resource.table_name}\".\"#{field}\" BETWEEN ? AND ?",
         
     | 
| 
      
 123 
     | 
    
         
            +
                                          param.first, param.last)
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
       103 
125 
     | 
    
         
             
                      when 'like'
         
     | 
| 
       104 
     | 
    
         
            -
                        resource = resource 
     | 
| 
      
 126 
     | 
    
         
            +
                        resource = resource
         
     | 
| 
      
 127 
     | 
    
         
            +
                                   .where("\"#{resource.table_name}\".\"#{field}\" LIKE ?",
         
     | 
| 
      
 128 
     | 
    
         
            +
                                          func[:param])
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                      when 'contains'
         
     | 
| 
      
 131 
     | 
    
         
            +
                        resource = resource
         
     | 
| 
      
 132 
     | 
    
         
            +
                                   .where("\"#{resource.table_name}\".\"#{field}\" LIKE ?",
         
     | 
| 
      
 133 
     | 
    
         
            +
                                          "%#{func[:param]}%")
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
       105 
135 
     | 
    
         
             
                      when 'null'
         
     | 
| 
       106 
136 
     | 
    
         
             
                        resource = resource.where(field => nil)
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                      when 'blank'
         
     | 
| 
      
 139 
     | 
    
         
            +
                        resource = resource.where(field => [nil, ''])
         
     | 
| 
       107 
140 
     | 
    
         
             
                      end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
       108 
142 
     | 
    
         
             
                    # if not function
         
     | 
| 
       109 
143 
     | 
    
         
             
                    else
         
     | 
| 
       110 
144 
     | 
    
         
             
                      values = condition.split(',')
         
     | 
| 
         @@ -117,7 +151,7 @@ module APIHelper::Filterable 
     | 
|
| 
       117 
151 
     | 
    
         
             
                return resource
         
     | 
| 
       118 
152 
     | 
    
         
             
              end
         
     | 
| 
       119 
153 
     | 
    
         | 
| 
       120 
     | 
    
         
            -
              #  
     | 
| 
      
 154 
     | 
    
         
            +
              # Returns a description of the 'fields' URL parameter
         
     | 
| 
       121 
155 
     | 
    
         
             
              def self.filter_param_desc(for_field: nil)
         
     | 
| 
       122 
156 
     | 
    
         
             
                if for_field.present?
         
     | 
| 
       123 
157 
     | 
    
         
             
                  "Filter data base on the '#{for_field}' field."
         
     | 
| 
         @@ -126,3 +160,9 @@ module APIHelper::Filterable 
     | 
|
| 
       126 
160 
     | 
    
         
             
                end
         
     | 
| 
       127 
161 
     | 
    
         
             
              end
         
     | 
| 
       128 
162 
     | 
    
         
             
            end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
            class String
         
     | 
| 
      
 165 
     | 
    
         
            +
              def to_bool
         
     | 
| 
      
 166 
     | 
    
         
            +
                self == 'true'
         
     | 
| 
      
 167 
     | 
    
         
            +
              end
         
     | 
| 
      
 168 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,16 +1,16 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'active_support'
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            # =  
     | 
| 
      
 3 
     | 
    
         
            +
            # = Includable
         
     | 
| 
       4 
4 
     | 
    
         
             
            #
         
     | 
| 
       5 
     | 
    
         
            -
            # Inclusion  
     | 
| 
       6 
     | 
    
         
            -
            #  
     | 
| 
       7 
     | 
    
         
            -
            #  
     | 
| 
      
 5 
     | 
    
         
            +
            # Inclusion lets your API returns not only the data of the primary resource,
         
     | 
| 
      
 6 
     | 
    
         
            +
            # but also resources that have relation to it. Includable APIs will also
         
     | 
| 
      
 7 
     | 
    
         
            +
            # support customising the resources included using the +include+ parameter.
         
     | 
| 
       8 
8 
     | 
    
         
             
            #
         
     | 
| 
       9 
9 
     | 
    
         
             
            # This design made references to the rules of <em>Inclusion of Related
         
     | 
| 
       10 
10 
     | 
    
         
             
            # Resources</em> in <em>JSON API</em>:
         
     | 
| 
       11 
11 
     | 
    
         
             
            # http://jsonapi.org/format/#fetching-includes
         
     | 
| 
       12 
12 
     | 
    
         
             
            #
         
     | 
| 
       13 
     | 
    
         
            -
            # For instance,  
     | 
| 
      
 13 
     | 
    
         
            +
            # For instance, articles can be requested with their comments along:
         
     | 
| 
       14 
14 
     | 
    
         
             
            #
         
     | 
| 
       15 
15 
     | 
    
         
             
            #   GET /articles?include=comments
         
     | 
| 
       16 
16 
     | 
    
         
             
            #
         
     | 
| 
         @@ -57,7 +57,7 @@ require 'active_support' 
     | 
|
| 
       57 
57 
     | 
    
         
             
            #     }
         
     | 
| 
       58 
58 
     | 
    
         
             
            #   ]
         
     | 
| 
       59 
59 
     | 
    
         
             
            #
         
     | 
| 
       60 
     | 
    
         
            -
            # instead of just 
     | 
| 
      
 60 
     | 
    
         
            +
            # instead of just the ids of each comment
         
     | 
| 
       61 
61 
     | 
    
         
             
            #
         
     | 
| 
       62 
62 
     | 
    
         
             
            #   [
         
     | 
| 
       63 
63 
     | 
    
         
             
            #     {
         
     | 
| 
         @@ -74,8 +74,8 @@ require 'active_support' 
     | 
|
| 
       74 
74 
     | 
    
         
             
            #     }
         
     | 
| 
       75 
75 
     | 
    
         
             
            #   ]
         
     | 
| 
       76 
76 
     | 
    
         
             
            #
         
     | 
| 
       77 
     | 
    
         
            -
            #  
     | 
| 
       78 
     | 
    
         
            -
            #  
     | 
| 
      
 77 
     | 
    
         
            +
            # Multiple related resources can be stated in a comma-separated list,
         
     | 
| 
      
 78 
     | 
    
         
            +
            # like this:
         
     | 
| 
       79 
79 
     | 
    
         
             
            #
         
     | 
| 
       80 
80 
     | 
    
         
             
            #   GET /articles/12?include=author,comments
         
     | 
| 
       81 
81 
     | 
    
         
             
            #
         
     | 
| 
         @@ -90,118 +90,243 @@ require 'active_support' 
     | 
|
| 
       90 
90 
     | 
    
         
             
            # or in your Grape API class:
         
     | 
| 
       91 
91 
     | 
    
         
             
            #
         
     | 
| 
       92 
92 
     | 
    
         
             
            #   class SampleAPI < Grape::API
         
     | 
| 
       93 
     | 
    
         
            -
            #      
     | 
| 
      
 93 
     | 
    
         
            +
            #     helpers APIHelper::Includable
         
     | 
| 
      
 94 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 95 
     | 
    
         
            +
            #
         
     | 
| 
      
 96 
     | 
    
         
            +
            # Then setup inclusion with +inclusion_for+ in the controller:
         
     | 
| 
      
 97 
     | 
    
         
            +
            #
         
     | 
| 
      
 98 
     | 
    
         
            +
            #   def index
         
     | 
| 
      
 99 
     | 
    
         
            +
            #     inclusion_for :post, default: true
         
     | 
| 
      
 100 
     | 
    
         
            +
            #     # ...
         
     | 
| 
       94 
101 
     | 
    
         
             
            #   end
         
     | 
| 
       95 
102 
     | 
    
         
             
            #
         
     | 
| 
       96 
     | 
    
         
            -
            #  
     | 
| 
      
 103 
     | 
    
         
            +
            # or in the Grape method if you're using it:
         
     | 
| 
       97 
104 
     | 
    
         
             
            #
         
     | 
| 
       98 
105 
     | 
    
         
             
            #   resources :posts do
         
     | 
| 
       99 
106 
     | 
    
         
             
            #     get do
         
     | 
| 
       100 
     | 
    
         
            -
            #       inclusion_for :post,  
     | 
| 
      
 107 
     | 
    
         
            +
            #       inclusion_for :post, default: true
         
     | 
| 
       101 
108 
     | 
    
         
             
            #       # ...
         
     | 
| 
       102 
109 
     | 
    
         
             
            #     end
         
     | 
| 
       103 
110 
     | 
    
         
             
            #   end
         
     | 
| 
       104 
111 
     | 
    
         
             
            #
         
     | 
| 
       105 
     | 
    
         
            -
            # This helper parses the +include+ and <tt>include[ 
     | 
| 
       106 
     | 
    
         
            -
            #  
     | 
| 
       107 
     | 
    
         
            -
            # 
     | 
| 
      
 112 
     | 
    
         
            +
            # This helper parses the +include+ and/or <tt>include[resource_name]</tt>
         
     | 
| 
      
 113 
     | 
    
         
            +
            # parameters and saves the results into +@inclusion+ for further usage.
         
     | 
| 
      
 114 
     | 
    
         
            +
            #
         
     | 
| 
      
 115 
     | 
    
         
            +
            # +Includable+ integrates with +Fieldsettable+ if used together, by:
         
     | 
| 
      
 116 
     | 
    
         
            +
            #
         
     | 
| 
      
 117 
     | 
    
         
            +
            # * Sliceing the included fields that dosen't appears in the fieldset - since
         
     | 
| 
      
 118 
     | 
    
         
            +
            #   the included resoure(s) are actually fields under the primary resorce,
         
     | 
| 
      
 119 
     | 
    
         
            +
            #   fieldset will be in charged to determine the fields to show. Thus, fields
         
     | 
| 
      
 120 
     | 
    
         
            +
            #   will be totally ignored if they aren't appeared in the fieldset, regardless
         
     | 
| 
      
 121 
     | 
    
         
            +
            #   if they are included or not.
         
     | 
| 
      
 122 
     | 
    
         
            +
            #
         
     | 
| 
      
 123 
     | 
    
         
            +
            # So notice that +inclusion_for+ should be set after +fieldset_for+ if both are
         
     | 
| 
      
 124 
     | 
    
         
            +
            # used!
         
     | 
| 
       108 
125 
     | 
    
         
             
            #
         
     | 
| 
       109 
     | 
    
         
            -
            # After  
     | 
| 
       110 
     | 
    
         
            -
            #  
     | 
| 
      
 126 
     | 
    
         
            +
            # After that +inclusion_for ...+ line, you can use the +inclusion+ helper
         
     | 
| 
      
 127 
     | 
    
         
            +
            # method to get the inclusion data of each request, and do something like this
         
     | 
| 
      
 128 
     | 
    
         
            +
            # in your controller:
         
     | 
| 
       111 
129 
     | 
    
         
             
            #
         
     | 
| 
       112 
     | 
    
         
            -
            #    
     | 
| 
      
 130 
     | 
    
         
            +
            #   @posts = Post.includes(inclusion(:post))
         
     | 
| 
       113 
131 
     | 
    
         
             
            #
         
     | 
| 
       114 
     | 
    
         
            -
            # The +inclusion+ helper method  
     | 
| 
      
 132 
     | 
    
         
            +
            # The +inclusion+ helper method will return data depending on the parameters
         
     | 
| 
      
 133 
     | 
    
         
            +
            # passed in, as the following example:
         
     | 
| 
       115 
134 
     | 
    
         
             
            #
         
     | 
| 
       116 
     | 
    
         
            -
            #   inclusion  
     | 
| 
       117 
     | 
    
         
            -
            #   inclusion(:post)  
     | 
| 
       118 
     | 
    
         
            -
            #   inclusion(:post, :author)  
     | 
| 
      
 135 
     | 
    
         
            +
            #   inclusion  # => { 'post' => ['author'] }
         
     | 
| 
      
 136 
     | 
    
         
            +
            #   inclusion(:post)  # => ['author']
         
     | 
| 
      
 137 
     | 
    
         
            +
            #   inclusion(:post, :author)  # => true
         
     | 
| 
      
 138 
     | 
    
         
            +
            #
         
     | 
| 
      
 139 
     | 
    
         
            +
            # And don't forget to set your API views or serializers with the help of
         
     | 
| 
      
 140 
     | 
    
         
            +
            # +inclusion+ to provide dynamic included resources!
         
     | 
| 
       119 
141 
     | 
    
         
             
            #
         
     | 
| 
       120 
142 
     | 
    
         
             
            # === API View with RABL
         
     | 
| 
       121 
143 
     | 
    
         
             
            #
         
     | 
| 
       122 
144 
     | 
    
         
             
            # If you're using RABL as the API view, it can be setup like this:
         
     | 
| 
       123 
145 
     | 
    
         
             
            #
         
     | 
| 
      
 146 
     | 
    
         
            +
            #   object @post
         
     | 
| 
      
 147 
     | 
    
         
            +
            #
         
     | 
| 
       124 
148 
     | 
    
         
             
            #   # set the includable and default inclusion fields of the view
         
     | 
| 
       125 
149 
     | 
    
         
             
            #   set_inclusion :post, default_includes: [:author]
         
     | 
| 
       126 
150 
     | 
    
         
             
            #
         
     | 
| 
       127 
151 
     | 
    
         
             
            #   # set the details for all includable fields
         
     | 
| 
       128 
152 
     | 
    
         
             
            #   set_inclusion_field :post, :author, :author_id
         
     | 
| 
      
 153 
     | 
    
         
            +
            #   set_inclusion_field :post, :comments, :comment_ids
         
     | 
| 
       129 
154 
     | 
    
         
             
            #
         
     | 
| 
       130 
155 
     | 
    
         
             
            #   # extends the partial to show included fields
         
     | 
| 
       131 
156 
     | 
    
         
             
            #   extends('extensions/includable_childs', locals: { self_resource: :post })
         
     | 
| 
      
 157 
     | 
    
         
            +
            #
         
     | 
| 
      
 158 
     | 
    
         
            +
            # --
         
     | 
| 
      
 159 
     | 
    
         
            +
            # TODO: provide an example of includable_childs.rabl
         
     | 
| 
      
 160 
     | 
    
         
            +
            # ++
         
     | 
| 
      
 161 
     | 
    
         
            +
            #
         
     | 
| 
       132 
162 
     | 
    
         
             
            module APIHelper::Includable
         
     | 
| 
       133 
163 
     | 
    
         
             
              extend ActiveSupport::Concern
         
     | 
| 
       134 
164 
     | 
    
         | 
| 
       135 
     | 
    
         
            -
              # Gets the include parameters, organize them into a +@inclusion+ hash 
     | 
| 
       136 
     | 
    
         
            -
              # inner-join queries and/or templates to render relation attributes included.
         
     | 
| 
       137 
     | 
    
         
            -
              # Following the URL rules of JSON API:
         
     | 
| 
       138 
     | 
    
         
            -
              # http://jsonapi.org/format/#fetching-includes
         
     | 
| 
      
 165 
     | 
    
         
            +
              # Gets the include parameters, organize them into a +@inclusion+ hash.
         
     | 
| 
       139 
166 
     | 
    
         
             
              #
         
     | 
| 
       140 
167 
     | 
    
         
             
              # Params:
         
     | 
| 
       141 
168 
     | 
    
         
             
              #
         
     | 
| 
       142 
169 
     | 
    
         
             
              # +resource+::
         
     | 
| 
       143 
170 
     | 
    
         
             
              #   +Symbol+ name of resource to receive the inclusion
         
     | 
| 
       144 
     | 
    
         
            -
               
     | 
| 
       145 
     | 
    
         
            -
             
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
             
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
       149 
     | 
    
         
            -
             
     | 
| 
       150 
     | 
    
         
            -
             
     | 
| 
       151 
     | 
    
         
            -
             
     | 
| 
      
 171 
     | 
    
         
            +
              #
         
     | 
| 
      
 172 
     | 
    
         
            +
              # +default+::
         
     | 
| 
      
 173 
     | 
    
         
            +
              #   +Boolean+ should this resource take the parameter from +include+ while no
         
     | 
| 
      
 174 
     | 
    
         
            +
              #             resourse name is specified?
         
     | 
| 
      
 175 
     | 
    
         
            +
              #
         
     | 
| 
      
 176 
     | 
    
         
            +
              # +permitted_includes+::
         
     | 
| 
      
 177 
     | 
    
         
            +
              #   +Array+ of +Symbol+s list of includable fields, permitting all by default
         
     | 
| 
      
 178 
     | 
    
         
            +
              #
         
     | 
| 
      
 179 
     | 
    
         
            +
              # +default_includes+::
         
     | 
| 
      
 180 
     | 
    
         
            +
              #   +Array+ of +Symbol+s list of fields to be included by default
         
     | 
| 
      
 181 
     | 
    
         
            +
              #
         
     | 
| 
      
 182 
     | 
    
         
            +
              # +defaults_to_permitted_includes+::
         
     | 
| 
      
 183 
     | 
    
         
            +
              #   +Boolean+ if set to true, +@inclusion+ will be set to all
         
     | 
| 
      
 184 
     | 
    
         
            +
              #   permitted_includes when the current resource's included fields
         
     | 
| 
      
 185 
     | 
    
         
            +
              #   isn't specified
         
     | 
| 
      
 186 
     | 
    
         
            +
              #
         
     | 
| 
      
 187 
     | 
    
         
            +
              def inclusion_for(resource, default: false,
         
     | 
| 
      
 188 
     | 
    
         
            +
                                          permitted_includes: [],
         
     | 
| 
      
 189 
     | 
    
         
            +
                                          defaults_to_permitted_includes: false,
         
     | 
| 
      
 190 
     | 
    
         
            +
                                          default_includes: [])
         
     | 
| 
      
 191 
     | 
    
         
            +
                @inclusion ||= ActiveSupport::HashWithIndifferentAccess.new
         
     | 
| 
      
 192 
     | 
    
         
            +
                @inclusion_specified ||= ActiveSupport::HashWithIndifferentAccess.new
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                # put the fields in place
         
     | 
| 
      
 195 
     | 
    
         
            +
                if params[:include].is_a?(Hash)
         
     | 
| 
      
 196 
     | 
    
         
            +
                  # get the specific resource inclusion fields from the "include" hash
         
     | 
| 
      
 197 
     | 
    
         
            +
                  @inclusion[resource] = params[:include][resource]
         
     | 
| 
      
 198 
     | 
    
         
            +
                  @inclusion_specified[resource] = true if params[:include][resource].present?
         
     | 
| 
      
 199 
     | 
    
         
            +
                elsif default
         
     | 
| 
      
 200 
     | 
    
         
            +
                  # or get the "include" string directly if this resource is th default one
         
     | 
| 
       152 
201 
     | 
    
         
             
                  @inclusion[resource] = params[:include]
         
     | 
| 
      
 202 
     | 
    
         
            +
                  @inclusion_specified[resource] = true if params[:include].present?
         
     | 
| 
       153 
203 
     | 
    
         
             
                end
         
     | 
| 
       154 
204 
     | 
    
         | 
| 
       155 
     | 
    
         
            -
                # splits the string into array 
     | 
| 
       156 
     | 
    
         
            -
                 
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
      
 205 
     | 
    
         
            +
                # splits the string into array
         
     | 
| 
      
 206 
     | 
    
         
            +
                if @inclusion[resource].present?
         
     | 
| 
      
 207 
     | 
    
         
            +
                  @inclusion[resource] = @inclusion[resource].split(',').map(&:to_s)
         
     | 
| 
      
 208 
     | 
    
         
            +
                elsif !@inclusion_specified[resource]
         
     | 
| 
      
 209 
     | 
    
         
            +
                  @inclusion[resource] = default_includes.map(&:to_s)
         
     | 
| 
      
 210 
     | 
    
         
            +
                end
         
     | 
| 
       158 
211 
     | 
    
         | 
| 
       159 
     | 
    
         
            -
             
     | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
       161 
     | 
    
         
            -
                @inclusion ||= {}
         
     | 
| 
       162 
     | 
    
         
            -
                @inclusion_field ||= {}
         
     | 
| 
       163 
     | 
    
         
            -
                @inclusion[resource] = default_includes if @inclusion[resource].blank?
         
     | 
| 
       164 
     | 
    
         
            -
              end
         
     | 
| 
      
 212 
     | 
    
         
            +
                if permitted_includes.present?
         
     | 
| 
      
 213 
     | 
    
         
            +
                  permitted_includes = permitted_includes.map(&:to_s)
         
     | 
| 
       165 
214 
     | 
    
         | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
     | 
    
         
            -
             
     | 
| 
       168 
     | 
    
         
            -
                return if (@fieldset.present? && @fieldset[self_resource].present? && !@fieldset[self_resource].include?(field))
         
     | 
| 
      
 215 
     | 
    
         
            +
                  # filter out unpermitted includes by intersecting them
         
     | 
| 
      
 216 
     | 
    
         
            +
                  @inclusion[resource] &= permitted_includes if @inclusion[resource].present?
         
     | 
| 
       169 
217 
     | 
    
         | 
| 
       170 
     | 
    
         
            -
             
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
       173 
     | 
    
         
            -
             
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
             
     | 
| 
       176 
     | 
    
         
            -
             
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
     | 
    
         
            -
                 
     | 
| 
       179 
     | 
    
         
            -
                @fieldset[self_resource].delete(field) if @fieldset[self_resource].present?
         
     | 
| 
      
 218 
     | 
    
         
            +
                  # set default inclusion to permitted_includes if needed
         
     | 
| 
      
 219 
     | 
    
         
            +
                  @inclusion[resource] = permitted_includes if @inclusion[resource].blank? &&
         
     | 
| 
      
 220 
     | 
    
         
            +
                                                               defaults_to_permitted_includes &&
         
     | 
| 
      
 221 
     | 
    
         
            +
                                                               !@inclusion_specified[resource]
         
     | 
| 
      
 222 
     | 
    
         
            +
                end
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
                if @fieldset.is_a?(Hash) && @fieldset[resource].present?
         
     | 
| 
      
 225 
     | 
    
         
            +
                  @inclusion[resource] &= @fieldset[resource]
         
     | 
| 
      
 226 
     | 
    
         
            +
                end
         
     | 
| 
       180 
227 
     | 
    
         
             
              end
         
     | 
| 
       181 
228 
     | 
    
         | 
| 
       182 
229 
     | 
    
         
             
              # Getter for the inclusion data.
         
     | 
| 
      
 230 
     | 
    
         
            +
              #
         
     | 
| 
      
 231 
     | 
    
         
            +
              # This method will act as a traditional getter of the inclusion data and
         
     | 
| 
      
 232 
     | 
    
         
            +
              # returns a hash containing fields for each resource if no parameter is
         
     | 
| 
      
 233 
     | 
    
         
            +
              # provided.
         
     | 
| 
      
 234 
     | 
    
         
            +
              #
         
     | 
| 
      
 235 
     | 
    
         
            +
              #   inclusion  # => { 'post' => ['author', 'comments'] }
         
     | 
| 
      
 236 
     | 
    
         
            +
              #
         
     | 
| 
      
 237 
     | 
    
         
            +
              # If one parameter - a specific resourse name is passed in, it will return an
         
     | 
| 
      
 238 
     | 
    
         
            +
              # array of relation names that should be included for that specific resourse.
         
     | 
| 
      
 239 
     | 
    
         
            +
              #
         
     | 
| 
      
 240 
     | 
    
         
            +
              #   inclusion(:post)  # => ['author', 'comments']
         
     | 
| 
      
 241 
     | 
    
         
            +
              #
         
     | 
| 
      
 242 
     | 
    
         
            +
              # And if one more parameter - a field name, is passed in, it will return a
         
     | 
| 
      
 243 
     | 
    
         
            +
              # boolen, determining if that relation should be included in the response.
         
     | 
| 
      
 244 
     | 
    
         
            +
              #
         
     | 
| 
      
 245 
     | 
    
         
            +
              #   inclusion(:post, :author)  # => true
         
     | 
| 
      
 246 
     | 
    
         
            +
              #
         
     | 
| 
       183 
247 
     | 
    
         
             
              def inclusion(resource = nil, field = nil)
         
     | 
| 
      
 248 
     | 
    
         
            +
                # act as a traditional getter if no parameters specified
         
     | 
| 
       184 
249 
     | 
    
         
             
                if resource.blank?
         
     | 
| 
       185 
     | 
    
         
            -
                  @inclusion ||=  
     | 
| 
      
 250 
     | 
    
         
            +
                  @inclusion ||= ActiveSupport::HashWithIndifferentAccess.new
         
     | 
| 
      
 251 
     | 
    
         
            +
             
     | 
| 
      
 252 
     | 
    
         
            +
                # returns the inclusion array if an specific resource is passed in
         
     | 
| 
       186 
253 
     | 
    
         
             
                elsif field.blank?
         
     | 
| 
       187 
     | 
    
         
            -
                   
     | 
| 
      
 254 
     | 
    
         
            +
                  inclusion[resource] || []
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
                # determine if a field is inculded
         
     | 
| 
       188 
257 
     | 
    
         
             
                else
         
     | 
| 
       189 
     | 
    
         
            -
                   
     | 
| 
       190 
     | 
    
         
            -
                  inclusion(resource).include?(field)
         
     | 
| 
      
 258 
     | 
    
         
            +
                  field = field.to_s
         
     | 
| 
      
 259 
     | 
    
         
            +
                  inclusion(resource).is_a?(Array) && inclusion(resource).include?(field)
         
     | 
| 
       191 
260 
     | 
    
         
             
                end
         
     | 
| 
       192 
261 
     | 
    
         
             
              end
         
     | 
| 
       193 
262 
     | 
    
         | 
| 
       194 
     | 
    
         
            -
              #  
     | 
| 
      
 263 
     | 
    
         
            +
              # View Helper to set the inclusion
         
     | 
| 
      
 264 
     | 
    
         
            +
              #
         
     | 
| 
      
 265 
     | 
    
         
            +
              # This is useful while using an resource view shared by multiple controllers,
         
     | 
| 
      
 266 
     | 
    
         
            +
              # this will ensure the +@inclusion+ instance variable presents, and can also
         
     | 
| 
      
 267 
     | 
    
         
            +
              # set the default included fields of a model for convenience, or the fields
         
     | 
| 
      
 268 
     | 
    
         
            +
              # that are permitted to be included for security.
         
     | 
| 
      
 269 
     | 
    
         
            +
              def set_inclusion(resource, default_includes: [], permitted_includes: [])
         
     | 
| 
      
 270 
     | 
    
         
            +
                @inclusion ||= ActiveSupport::HashWithIndifferentAccess.new
         
     | 
| 
      
 271 
     | 
    
         
            +
                @inclusion_field ||= ActiveSupport::HashWithIndifferentAccess.new
         
     | 
| 
      
 272 
     | 
    
         
            +
                @inclusion[resource] = default_includes.map(&:to_s) if @inclusion[resource].blank? &&
         
     | 
| 
      
 273 
     | 
    
         
            +
                                                                       !@inclusion_specified[resource]
         
     | 
| 
      
 274 
     | 
    
         
            +
                @inclusion[resource] &= permitted_includes.map(&:to_s) if permitted_includes.present?
         
     | 
| 
      
 275 
     | 
    
         
            +
              end
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
              # View Helper to set the inclusion details
         
     | 
| 
      
 278 
     | 
    
         
            +
              #
         
     | 
| 
      
 279 
     | 
    
         
            +
              # Params:
         
     | 
| 
      
 280 
     | 
    
         
            +
              #
         
     | 
| 
      
 281 
     | 
    
         
            +
              # +resource+::
         
     | 
| 
      
 282 
     | 
    
         
            +
              #   +Symbol+ name of the resource to receive the inclusion field data
         
     | 
| 
      
 283 
     | 
    
         
            +
              #
         
     | 
| 
      
 284 
     | 
    
         
            +
              # +field+::
         
     | 
| 
      
 285 
     | 
    
         
            +
              #   +Symbol+ the field name of the relatiion that can be included
         
     | 
| 
      
 286 
     | 
    
         
            +
              #
         
     | 
| 
      
 287 
     | 
    
         
            +
              # +id_field+::
         
     | 
| 
      
 288 
     | 
    
         
            +
              #   +Symbol+ the field to use (normally suffixed with "_id") if the object
         
     | 
| 
      
 289 
     | 
    
         
            +
              #   isn't included
         
     | 
| 
      
 290 
     | 
    
         
            +
              #
         
     | 
| 
      
 291 
     | 
    
         
            +
              # +resource_name+::
         
     | 
| 
      
 292 
     | 
    
         
            +
              #   +Symbol+ the name of the child resource, can be used to determine which
         
     | 
| 
      
 293 
     | 
    
         
            +
              #   view template should be extended for rendering that child node and also
         
     | 
| 
      
 294 
     | 
    
         
            +
              #   can shown in the response metadata as well
         
     | 
| 
      
 295 
     | 
    
         
            +
              #
         
     | 
| 
      
 296 
     | 
    
         
            +
              # +resources_url+::
         
     | 
| 
      
 297 
     | 
    
         
            +
              #   +String+ the resources URL of the child resource, can be used to be shown
         
     | 
| 
      
 298 
     | 
    
         
            +
              #   in the metadata for the clients' convenience to learn ablou the API
         
     | 
| 
      
 299 
     | 
    
         
            +
              #
         
     | 
| 
      
 300 
     | 
    
         
            +
              def set_inclusion_field(resource, field, id_field, resource_name: nil,
         
     | 
| 
      
 301 
     | 
    
         
            +
                                                                 resources_url: nil)
         
     | 
| 
      
 302 
     | 
    
         
            +
                @inclusion_field ||= ActiveSupport::HashWithIndifferentAccess.new
         
     | 
| 
      
 303 
     | 
    
         
            +
                @inclusion_field[resource] ||= ActiveSupport::HashWithIndifferentAccess.new
         
     | 
| 
      
 304 
     | 
    
         
            +
                @inclusion_field[resource][field] = {
         
     | 
| 
      
 305 
     | 
    
         
            +
                  field: field,
         
     | 
| 
      
 306 
     | 
    
         
            +
                  id_field: id_field,
         
     | 
| 
      
 307 
     | 
    
         
            +
                  resource_name: resource_name,
         
     | 
| 
      
 308 
     | 
    
         
            +
                  resources_url: resources_url
         
     | 
| 
      
 309 
     | 
    
         
            +
                }
         
     | 
| 
      
 310 
     | 
    
         
            +
              end
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
              # Returns the description of the 'include' URL parameter
         
     | 
| 
       195 
313 
     | 
    
         
             
              def self.include_param_desc(example: nil, default: nil)
         
     | 
| 
       196 
314 
     | 
    
         
             
                if default.present?
         
     | 
| 
       197 
315 
     | 
    
         
             
                  desc = "Returning compound documents that include specific associated objects, defaults to '#{default}'."
         
     | 
| 
       198 
316 
     | 
    
         
             
                else
         
     | 
| 
       199 
317 
     | 
    
         
             
                  desc = "Returning compound documents that include specific associated objects."
         
     | 
| 
       200 
318 
     | 
    
         
             
                end
         
     | 
| 
      
 319 
     | 
    
         
            +
             
     | 
| 
       201 
320 
     | 
    
         
             
                if example.present?
         
     | 
| 
       202 
321 
     | 
    
         
             
                  "#{desc} Example value: '#{example}'"
         
     | 
| 
       203 
322 
     | 
    
         
             
                else
         
     | 
| 
       204 
323 
     | 
    
         
             
                  desc
         
     | 
| 
       205 
324 
     | 
    
         
             
                end
         
     | 
| 
       206 
325 
     | 
    
         
             
              end
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
              included do
         
     | 
| 
      
 328 
     | 
    
         
            +
                if defined? helper_method
         
     | 
| 
      
 329 
     | 
    
         
            +
                  helper_method :inclusion, :set_inclusion, :set_inclusion_field
         
     | 
| 
      
 330 
     | 
    
         
            +
                end
         
     | 
| 
      
 331 
     | 
    
         
            +
              end
         
     | 
| 
       207 
332 
     | 
    
         
             
            end
         
     | 
    
        data/lib/api_helper/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: api_helper
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.3
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Neson
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: exe
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2015-06- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2015-06-14 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: bundler
         
     | 
| 
         @@ -38,6 +38,20 @@ dependencies: 
     | 
|
| 
       38 
38 
     | 
    
         
             
                - - ">="
         
     | 
| 
       39 
39 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       40 
40 
     | 
    
         
             
                    version: '0'
         
     | 
| 
      
 41 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 42 
     | 
    
         
            +
              name: appraisal
         
     | 
| 
      
 43 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 44 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 45 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 46 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 47 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 48 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 49 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 50 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
       41 
55 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       42 
56 
     | 
    
         
             
              name: rspec
         
     | 
| 
       43 
57 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -52,6 +66,48 @@ dependencies: 
     | 
|
| 
       52 
66 
     | 
    
         
             
                - - ">="
         
     | 
| 
       53 
67 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       54 
68 
     | 
    
         
             
                    version: '0'
         
     | 
| 
      
 69 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 70 
     | 
    
         
            +
              name: byebug
         
     | 
| 
      
 71 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 72 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 73 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 74 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 75 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 76 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 77 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 78 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 79 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 80 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 81 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 82 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 83 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 84 
     | 
    
         
            +
              name: activerecord
         
     | 
| 
      
 85 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 86 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 87 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 88 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 89 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 90 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 91 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 92 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 93 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 94 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 95 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 96 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 97 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 98 
     | 
    
         
            +
              name: sqlite3
         
     | 
| 
      
 99 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 100 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 101 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 102 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 103 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 104 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 105 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 106 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 107 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 108 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 109 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 110 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
       55 
111 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       56 
112 
     | 
    
         
             
              name: activesupport
         
     | 
| 
       57 
113 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -76,12 +132,20 @@ files: 
     | 
|
| 
       76 
132 
     | 
    
         
             
            - ".gitignore"
         
     | 
| 
       77 
133 
     | 
    
         
             
            - ".rspec"
         
     | 
| 
       78 
134 
     | 
    
         
             
            - ".travis.yml"
         
     | 
| 
      
 135 
     | 
    
         
            +
            - Appraisals
         
     | 
| 
       79 
136 
     | 
    
         
             
            - Gemfile
         
     | 
| 
       80 
137 
     | 
    
         
             
            - README.md
         
     | 
| 
       81 
138 
     | 
    
         
             
            - Rakefile
         
     | 
| 
       82 
139 
     | 
    
         
             
            - api_helper.gemspec
         
     | 
| 
       83 
140 
     | 
    
         
             
            - bin/console
         
     | 
| 
       84 
141 
     | 
    
         
             
            - bin/setup
         
     | 
| 
      
 142 
     | 
    
         
            +
            - examples/includable_childs.rabl
         
     | 
| 
      
 143 
     | 
    
         
            +
            - gemfiles/grape_0.10.0.gemfile
         
     | 
| 
      
 144 
     | 
    
         
            +
            - gemfiles/grape_0.11.0.gemfile
         
     | 
| 
      
 145 
     | 
    
         
            +
            - gemfiles/rails_4.0.0.gemfile
         
     | 
| 
      
 146 
     | 
    
         
            +
            - gemfiles/rails_4.1.0.gemfile
         
     | 
| 
      
 147 
     | 
    
         
            +
            - gemfiles/rails_4.1.8.gemfile
         
     | 
| 
      
 148 
     | 
    
         
            +
            - gemfiles/rails_4.2.0.gemfile
         
     | 
| 
       85 
149 
     | 
    
         
             
            - lib/api_helper.rb
         
     | 
| 
       86 
150 
     | 
    
         
             
            - lib/api_helper/fieldsettable.rb
         
     | 
| 
       87 
151 
     | 
    
         
             
            - lib/api_helper/filterable.rb
         
     | 
| 
         @@ -114,3 +178,4 @@ signing_key: 
     | 
|
| 
       114 
178 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       115 
179 
     | 
    
         
             
            summary: Helpers for creating standard web API.
         
     | 
| 
       116 
180 
     | 
    
         
             
            test_files: []
         
     | 
| 
      
 181 
     | 
    
         
            +
            has_rdoc: 
         
     |