model-api 0.8.10 → 0.8.11

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f4236690ba6188e94302365bcb54af72c44d9895
4
- data.tar.gz: 8feab210c4e863f0d031ec4a4ec65f7fad683fbd
3
+ metadata.gz: 4f14172aa6fcaa7f2c314d673e4295338493588b
4
+ data.tar.gz: 43e8a3a180fb05ca4d527b953e78e091ecdc75fb
5
5
  SHA512:
6
- metadata.gz: 6ad9de6daf542958341c2f86f50362a3b554bba9b74e10883a20c6905424f6b3e04b3c63660b48a178a626ce36baac70932f35b58c1533ceb91885346c2eaba6
7
- data.tar.gz: 07725bfd70fd203020847b0c07cbd68fcdeb50db2917d999484c6a57d649388df07041e1432ad0cfb99ef86c844cc9853ea58573a353e09573fecfedd86faba0
6
+ metadata.gz: 50b16368bf036477dbf671d3b0e528e6533ca358a35ae917f4d8ff2408c61470fa161c3c1399850bba0ba0b5bd797c33bd80c81ebc806ece1fa5303971a36020
7
+ data.tar.gz: 7566d5be7fc86688cf8e09bfa58bab47b644b81e2c87f9859e05edfbd08c9dee37246f2294dae8300f411a9b1751624cd908a1a5a3fb74b113b5b9664e6f66bb
data/README.md CHANGED
@@ -9,32 +9,35 @@ Developing REST API's in a conventional manner involves many challenges. Betwee
9
9
 
10
10
  With model-api, you can:
11
11
  * Consolidate your payload and response metadata for a given resource in the ActiveRecord model.
12
+ * Reduce the lines of code required to implement your Rails-based Rest API dramatically.
13
+ * Generate OpenAPI documentation guaranteed to be in sync with what your API actually supports.
12
14
  * Set up easily-configurable filtering, pagination, sorting, and HATEOAS link generation.
13
15
  * Render, link, create, search upon, and sort upon your resources' associated objects with ease.
14
- * Easily leverage the ActiveRecord validation rules present in your application's models to
15
- validate calls to your API.
16
- * Automatically generate OpenAPI documentation with each deployment that's guaranteed to be in
17
- sync with what your API actually supports.
18
- * Reduce the lines of code required to implement your Rails-based Rest API dramatically.
16
+ * Leverage ActiveRecord validation rules in your application's models to validate API calls.
17
+ * Effortlessly support JSON and XML input / output formats together in the same API.
18
+ * Use Java-style camel-case for API content while utilizing Ruby underscore convention internally.
19
19
 
20
20
  ## Guides
21
21
  This README file is intended to provide a brief introduction. For more detailed information,
22
22
  the following guides are available:
23
- * [Guide to `api_metadata` options](doc/api_metadata.md)
24
- * [Guide to `model_metadata` options](doc/api_metadata.md)
25
- * [Managing data access in `model-api`](doc/api_metadata.md)
23
+ * [Guide to `api_attributes` metadata](doc/api_attributes.md)
24
+ * [Guide to `api_model` metadata](doc/api_model.md)
25
+ * [Managing data access in `model-api`](doc/managing_data_access.md)
26
+
27
+ General information on the API (including enumerated constants, etc.) can be found here:
28
+ * [General gem usage information](doc/general_info.md)
26
29
 
27
30
  ## Installation
28
31
 
29
32
  Put this in your Gemfile:
30
33
 
31
34
  ``` ruby
32
- gem 'open-api'
35
+ gem 'model-api'
33
36
  ```
34
37
 
35
38
  ## Configuration
36
39
 
37
- The `model-api` gem doesn't require configuration. However, if you plan to generate OpenAPI
40
+ The model-api gem doesn't require configuration. However, if you plan to generate OpenAPI
38
41
  documentation, add an `open_api.rb` file to `config/initializers` and configure as follows:
39
42
 
40
43
  ``` ruby
@@ -78,9 +81,14 @@ class Book < ActiveRecord::Base
78
81
  validates :name, presence: true, uniqueness: true, length: { maximum: 50 }
79
82
  validates :description, length: { maximum: 250 }
80
83
  validates :isbn, presence: true, uniqueness: true, length: { maximum: 13 }
81
-
84
+
85
+ # Define model-level rules and metadata associated with the REST API.
86
+ api_model(
87
+ base_query: ->(opts) { opts[:admin] ? Book.where(public: true) : Book.all }
88
+ )
89
+
82
90
  # Define the attributes exposed via the REST API.
83
- api_attributes \
91
+ api_attributes(
84
92
  id: { filter: true, sort: true },
85
93
  name: { filter: true, sort: true },
86
94
  description: {},
@@ -90,10 +98,14 @@ class Book < ActiveRecord::Base
90
98
  },
91
99
  created_at: { read_only: true, filter: true },
92
100
  updated_at: { read_only: true, filter: true }
101
+ )
93
102
 
94
103
  end
95
104
  ```
96
- An explanation of the options used in the `api_attributes` example above:
105
+ An explanation of the options used in the [`api_model`](doc/api_model.md) example above:
106
+ * `base_query` - Limit data exposed by the API based on context (e.g. current user).
107
+
108
+ An explanation of the options used in the [`api_attributes`](doc/api_attributes.md) example above:
97
109
  * `filter` - Allow filtering by query string parameters (e.g. `?id=123`).
98
110
  * `sort` - Allow use of this column in the sort_by parameter.
99
111
  * `read_only` - Disallow column updates (via `POST`, `PUT`, or `PATCH`).
@@ -188,6 +188,9 @@ module ModelApi
188
188
  default_link_options = request.params.to_h.symbolize_keys
189
189
  opts[:collection_link_options] ||= default_link_options
190
190
  opts[:object_link_options] ||= default_link_options
191
+ if default_link_options[:exclude_associations].present?
192
+ opts[:exclude_associations] ||= default_link_options[:exclude_associations]
193
+ end
191
194
  end
192
195
  opts[:options_initialized] ||= true
193
196
  opts
@@ -419,10 +419,49 @@ module ModelApi
419
419
  includes << attr_metadata[:key] if attr_metadata[:type] == :association
420
420
  end
421
421
  includes = includes.compact.uniq
422
+ includes = remove_excluded_associations(includes, opts)
422
423
  collection = collection.includes(includes) if includes.present?
423
424
  collection
424
425
  end
425
426
 
427
+ # Does not eager load associations mentioned in the exclude_associations
428
+ # array defined by user.
429
+ def remove_excluded_associations(includes, opts)
430
+ includes_dup = includes.compact.uniq.deep_dup
431
+ exclude_associations = opts[:exclude_associations]
432
+ return includes_dup unless exclude_associations.present?
433
+ exclude_associations.each do |association|
434
+ remove_association_from_array(includes_dup, association.to_sym)
435
+ end
436
+ includes_dup
437
+ end
438
+
439
+ # If the association is present in array form (in collection_includes) delete it.
440
+ # Then loop over the array elements to remove the association incase of nested associations.
441
+ def remove_association_from_array(array_collection, association)
442
+ array_collection.delete(association)
443
+ array_collection.each_with_index do |collection, i|
444
+ if collection.is_a?(Hash)
445
+ array_collection[i] = remove_association_from_hash(collection, association)
446
+ end
447
+ end
448
+ array_collection
449
+ end
450
+
451
+ # Incase of nested associations (in collection_inlcudes) delete the key with the association name
452
+ # and then loop over the collection to delete associations present as element of the array if any
453
+ def remove_association_from_hash(hash_collection, association)
454
+ if hash_collection.keys.include?(association)
455
+ hash_collection.delete(association)
456
+ else
457
+ hash_collection.each do |key, value|
458
+ hash_collection[key] =
459
+ remove_association_from_array(value, association) if value.is_a?(Array)
460
+ end
461
+ end
462
+ hash_collection
463
+ end
464
+
426
465
  def find_class(obj, opts = {})
427
466
  return nil if obj.nil?
428
467
  opts[:class] || (obj.respond_to?(:klass) ? obj.klass : obj.class)
@@ -459,6 +498,13 @@ module ModelApi
459
498
  metadata
460
499
  end
461
500
 
501
+ def exclude_associations_metadata(metadata, obj, opts = {})
502
+ exclude_associations = opts[:exclude_associations].try(:map, &:to_sym)
503
+ if exclude_associations.present?
504
+ (exclude_associations.include?(obj.table_name) || exclude_associations.include?(metadata[:key]))
505
+ end
506
+ end
507
+
462
508
  def include_item?(metadata, obj, operation, opts = {})
463
509
  return false unless metadata.is_a?(Hash)
464
510
  return false unless include_item_meets_admin_criteria?(metadata, obj, operation, opts)
@@ -467,6 +513,7 @@ module ModelApi
467
513
  return eval_bool(obj, metadata[:sort], opts) if operation == :sort
468
514
  return false unless include_item_meets_read_write_criteria?(metadata, obj, operation, opts)
469
515
  return false unless include_item_meets_incl_excl_criteria?(metadata, obj, operation, opts)
516
+ return false if exclude_associations_metadata(metadata, obj, opts)
470
517
  true
471
518
  end
472
519
 
data/model-api.gemspec CHANGED
@@ -3,7 +3,7 @@ $:.unshift lib unless $:.include?(lib)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = 'model-api'
6
- s.version = '0.8.10'
6
+ s.version = '0.8.11'
7
7
  s.summary = 'Create easy REST API\'s using metadata inside your ActiveRecord models'
8
8
  s.description = 'Ruby gem allowing Ruby on Rails developers to create REST API’s using ' \
9
9
  'metadata defined inside their ActiveRecord models.'
metadata CHANGED
@@ -1,61 +1,61 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: model-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.10
4
+ version: 0.8.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Mead
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-01 00:00:00.000000000 Z
11
+ date: 2017-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '4.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: open-api
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: 0.8.4
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.8.4
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec-rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '3.5'
48
- - - '>='
48
+ - - ">="
49
49
  - !ruby/object:Gem::Version
50
50
  version: 3.5.2
51
51
  type: :development
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
- - - ~>
55
+ - - "~>"
56
56
  - !ruby/object:Gem::Version
57
57
  version: '3.5'
58
- - - '>='
58
+ - - ">="
59
59
  - !ruby/object:Gem::Version
60
60
  version: 3.5.2
61
61
  description: Ruby gem allowing Ruby on Rails developers to create REST API’s using
@@ -90,17 +90,17 @@ require_paths:
90
90
  - lib
91
91
  required_ruby_version: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - '>='
93
+ - - ">="
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
96
  required_rubygems_version: !ruby/object:Gem::Requirement
97
97
  requirements:
98
- - - '>='
98
+ - - ">="
99
99
  - !ruby/object:Gem::Version
100
100
  version: '0'
101
101
  requirements: []
102
102
  rubyforge_project:
103
- rubygems_version: 2.4.6
103
+ rubygems_version: 2.5.2
104
104
  signing_key:
105
105
  specification_version: 4
106
106
  summary: Create easy REST API's using metadata inside your ActiveRecord models