grape_fast_jsonapi 0.2.0 → 0.2.6

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
  SHA256:
3
- metadata.gz: 38ad3fb865f43aa0c089abf0136617191d3dbf8fa10d3dff3798537312026851
4
- data.tar.gz: 44f09504170ee1b3ec39be3d11784adaf5255b867693c77850d5089b2b2cecf5
3
+ metadata.gz: 6026dd876923e91c284ef3c379b4393ec47495485aab633827510601ac0b6355
4
+ data.tar.gz: 5a43fc86d8e7839774bd5fd56ff2c76fbef8d9d9e20b194c059e12d330ac6117
5
5
  SHA512:
6
- metadata.gz: c6d628fe38e31362949ee2c9e7fbf9d866fe5e99ee910aa16f8dc533da1ee54ec5e8af949d688b194fbe783d258fe5ac09e20ee5a23d60ba8b1aa61335f4d1f7
7
- data.tar.gz: c6f7ec14e0e3d67e9dd707dd99b563408d62526f4188c114198c53a8b053a0075c2c7f98bea028cf1baa797a613465ba7b0b8be16e431624bc961ae6dd00804c
6
+ metadata.gz: fdc6ee51194b78acda16f8a4bae6d0d0644c2b796918d6786741b055fe3679074735755ff82ac47e8c39cea0152ecd348a5ebbfebb000d4abb4f0b70aa55b1b7
7
+ data.tar.gz: 9bd438e0174f856064eb568953932fa786c569afbefeb52ea7b8680247e2236a256a945189c9925517f4d5bce8803b800cdbcadf5456a434999fc53e9f82b798
@@ -7,9 +7,11 @@ jobs:
7
7
  build:
8
8
  docker:
9
9
  # specify the version you desire here
10
- - image: circleci/ruby:2.5.3-node-browsers
10
+ - image: circleci/ruby:2.6.3-node-browsers
11
11
  environment:
12
12
  RAILS_ENV: test
13
+ PGHOST: 127.0.0.1
14
+ PGUSER: root
13
15
 
14
16
  # Specify service dependencies here if necessary
15
17
  # CircleCI maintains a library of pre-built images
@@ -1,13 +1,41 @@
1
1
  ## Changelog
2
2
 
3
- ### 0.2.1 (Next)
3
+ ### v0.2.7 (Next)
4
4
 
5
5
  * Your contribution here.
6
6
 
7
+ ### v0.2.6 (June 20, 2020)
8
+
9
+ * [#14](https://github.com/EmCousin/grape_fast_jsonapi/pull/14) and [#21](https://github.com/EmCousin/grape_fast_jsonapi/pull/21) - Fixes to swagger parser: Respect `:key` setting, fix column type rendering, allow adding to schema - [@vincentvanbush](https://github.com/vincentvanbush) and [@nathanvda](https://github.com/nathanvda)
10
+
11
+ ### v0.2.5 (January 23, 2020)
12
+
13
+ * [#18](https://github.com/EmCousin/grape_fast_jsonapi/pull/18) - Revert to model_name instead of class-name - [@dblommesteijn](https://github.com/dblommesteijn)
14
+
15
+ Note : This PR fixes a bug when serializing a ActiveRecord::Relation instance, the formatter was looking for a formatter `ActiveRecord::RelationSerializer` serializer that doesn't exist, insteafd of looking for the serializer corresponding to its model name.
16
+
17
+ * Security updates
18
+
19
+ ### v0.2.4 (December 16, 2019)
20
+
21
+ * [#15](https://github.com/EmCousin/grape_fast_jsonapi/pull/15) - Handle serializers which don't have any attributes - [@vesan](https://github.com/vesan)
22
+
23
+ ### v0.2.3 (December 12, 2019)
24
+
25
+ * Reverted v0.2.2 and bumped `loofah` using `dependabot` - [@EmCousin](https://github.com/EmCousin).
26
+
27
+ ### v0.2.2 (December 12, 2019)
28
+
29
+ * Fixed low severity vulnerabiliy issue with `loofah` dependency - [@EmCousin](https://github.com/EmCousin).
30
+
31
+ ### v0.2.1 (September 18, 2019)
32
+
33
+ * [#12](https://github.com/EmCousin/grape_fast_jsonapi/pull/12) - Removed call to `rails` and fixed a potential security issue - [@EmCousin](https://github.com/EmCousin).
34
+
7
35
  ### v0.2.0 (February 8, 2019)
8
36
 
9
37
  * [#5](https://github.com/EmCousin/grape_fast_jsonapi/pull/5): Provide custom Grape Swagger parser for fast_jsonapi object serializers, as well as unit test coverage - [@EmCousin](https://github.com/EmCousin)
10
- * [#6](https://github.com/EmCousin/grape_fast_jsonapi/pull/6) - Fix to make the parser compatible with latest version of fast_jsonapi (1.5 at date) - @rromanchuk](https://github.com/rromanchuk).
38
+ * [#6](https://github.com/EmCousin/grape_fast_jsonapi/pull/6) - Fix to make the parser compatible with latest version of fast_jsonapi (1.5 at date) - [@rromanchuk](https://github.com/rromanchuk).
11
39
 
12
40
  ### v0.1.0
13
41
 
@@ -1,163 +1,187 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grape_fast_jsonapi (0.2.0)
4
+ grape_fast_jsonapi (0.2.6)
5
5
  fast_jsonapi (>= 1.5)
6
6
  grape
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- actioncable (5.2.2)
12
- actionpack (= 5.2.2)
11
+ actioncable (6.0.3.2)
12
+ actionpack (= 6.0.3.2)
13
13
  nio4r (~> 2.0)
14
14
  websocket-driver (>= 0.6.1)
15
- actionmailer (5.2.2)
16
- actionpack (= 5.2.2)
17
- actionview (= 5.2.2)
18
- activejob (= 5.2.2)
15
+ actionmailbox (6.0.3.2)
16
+ actionpack (= 6.0.3.2)
17
+ activejob (= 6.0.3.2)
18
+ activerecord (= 6.0.3.2)
19
+ activestorage (= 6.0.3.2)
20
+ activesupport (= 6.0.3.2)
21
+ mail (>= 2.7.1)
22
+ actionmailer (6.0.3.2)
23
+ actionpack (= 6.0.3.2)
24
+ actionview (= 6.0.3.2)
25
+ activejob (= 6.0.3.2)
19
26
  mail (~> 2.5, >= 2.5.4)
20
27
  rails-dom-testing (~> 2.0)
21
- actionpack (5.2.2)
22
- actionview (= 5.2.2)
23
- activesupport (= 5.2.2)
24
- rack (~> 2.0)
28
+ actionpack (6.0.3.2)
29
+ actionview (= 6.0.3.2)
30
+ activesupport (= 6.0.3.2)
31
+ rack (~> 2.0, >= 2.0.8)
25
32
  rack-test (>= 0.6.3)
26
33
  rails-dom-testing (~> 2.0)
27
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
28
- actionview (5.2.2)
29
- activesupport (= 5.2.2)
34
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
35
+ actiontext (6.0.3.2)
36
+ actionpack (= 6.0.3.2)
37
+ activerecord (= 6.0.3.2)
38
+ activestorage (= 6.0.3.2)
39
+ activesupport (= 6.0.3.2)
40
+ nokogiri (>= 1.8.5)
41
+ actionview (6.0.3.2)
42
+ activesupport (= 6.0.3.2)
30
43
  builder (~> 3.1)
31
44
  erubi (~> 1.4)
32
45
  rails-dom-testing (~> 2.0)
33
- rails-html-sanitizer (~> 1.0, >= 1.0.3)
34
- activejob (5.2.2)
35
- activesupport (= 5.2.2)
46
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
47
+ activejob (6.0.3.2)
48
+ activesupport (= 6.0.3.2)
36
49
  globalid (>= 0.3.6)
37
- activemodel (5.2.2)
38
- activesupport (= 5.2.2)
39
- activerecord (5.2.2)
40
- activemodel (= 5.2.2)
41
- activesupport (= 5.2.2)
42
- arel (>= 9.0)
43
- activestorage (5.2.2)
44
- actionpack (= 5.2.2)
45
- activerecord (= 5.2.2)
50
+ activemodel (6.0.3.2)
51
+ activesupport (= 6.0.3.2)
52
+ activerecord (6.0.3.2)
53
+ activemodel (= 6.0.3.2)
54
+ activesupport (= 6.0.3.2)
55
+ activestorage (6.0.3.2)
56
+ actionpack (= 6.0.3.2)
57
+ activejob (= 6.0.3.2)
58
+ activerecord (= 6.0.3.2)
46
59
  marcel (~> 0.3.1)
47
- activesupport (5.2.2)
60
+ activesupport (6.0.3.2)
48
61
  concurrent-ruby (~> 1.0, >= 1.0.2)
49
62
  i18n (>= 0.7, < 2)
50
63
  minitest (~> 5.1)
51
64
  tzinfo (~> 1.1)
52
- arel (9.0.0)
53
- axiom-types (0.1.1)
54
- descendants_tracker (~> 0.0.4)
55
- ice_nine (~> 0.11.0)
56
- thread_safe (~> 0.3, >= 0.3.1)
57
- builder (3.2.3)
58
- coercible (1.0.0)
59
- descendants_tracker (~> 0.0.1)
60
- concurrent-ruby (1.1.4)
61
- crass (1.0.4)
62
- descendants_tracker (0.0.4)
63
- thread_safe (~> 0.3, >= 0.3.1)
65
+ zeitwerk (~> 2.2, >= 2.2.2)
66
+ builder (3.2.4)
67
+ concurrent-ruby (1.1.6)
68
+ crass (1.0.6)
64
69
  diff-lcs (1.3)
65
- equalizer (0.0.11)
66
- erubi (1.8.0)
70
+ dry-configurable (0.9.0)
71
+ concurrent-ruby (~> 1.0)
72
+ dry-core (~> 0.4, >= 0.4.7)
73
+ dry-container (0.7.2)
74
+ concurrent-ruby (~> 1.0)
75
+ dry-configurable (~> 0.1, >= 0.1.3)
76
+ dry-core (0.4.9)
77
+ concurrent-ruby (~> 1.0)
78
+ dry-equalizer (0.3.0)
79
+ dry-inflector (0.2.0)
80
+ dry-logic (1.0.5)
81
+ concurrent-ruby (~> 1.0)
82
+ dry-core (~> 0.2)
83
+ dry-equalizer (~> 0.2)
84
+ dry-types (1.2.2)
85
+ concurrent-ruby (~> 1.0)
86
+ dry-container (~> 0.3)
87
+ dry-core (~> 0.4, >= 0.4.4)
88
+ dry-equalizer (~> 0.3)
89
+ dry-inflector (~> 0.1, >= 0.1.2)
90
+ dry-logic (~> 1.0, >= 1.0.2)
91
+ erubi (1.9.0)
67
92
  fast_jsonapi (1.5)
68
93
  activesupport (>= 4.2)
69
94
  globalid (0.4.2)
70
95
  activesupport (>= 4.2.0)
71
- grape (1.2.3)
96
+ grape (1.3.0)
72
97
  activesupport
73
98
  builder
99
+ dry-types (>= 1.1)
74
100
  mustermann-grape (~> 1.0.0)
75
101
  rack (>= 1.3.0)
76
102
  rack-accept
77
- virtus (>= 1.0.0)
78
- i18n (1.5.3)
103
+ i18n (1.8.3)
79
104
  concurrent-ruby (~> 1.0)
80
- ice_nine (0.11.2)
81
- loofah (2.2.3)
105
+ loofah (2.6.0)
82
106
  crass (~> 1.0.2)
83
107
  nokogiri (>= 1.5.9)
84
108
  mail (2.7.1)
85
109
  mini_mime (>= 0.1.1)
86
110
  marcel (0.3.3)
87
111
  mimemagic (~> 0.3.2)
88
- method_source (0.9.2)
89
- mimemagic (0.3.3)
90
- mini_mime (1.0.1)
112
+ method_source (1.0.0)
113
+ mimemagic (0.3.5)
114
+ mini_mime (1.0.2)
91
115
  mini_portile2 (2.4.0)
92
- minitest (5.11.3)
93
- mustermann (1.0.3)
94
- mustermann-grape (1.0.0)
95
- mustermann (~> 1.0.0)
96
- nio4r (2.3.1)
97
- nokogiri (1.10.1)
116
+ minitest (5.14.1)
117
+ mustermann (1.1.1)
118
+ ruby2_keywords (~> 0.0.1)
119
+ mustermann-grape (1.0.1)
120
+ mustermann (>= 1.0.0)
121
+ nio4r (2.5.2)
122
+ nokogiri (1.10.9)
98
123
  mini_portile2 (~> 2.4.0)
99
- rack (2.0.6)
124
+ rack (2.2.3)
100
125
  rack-accept (0.4.5)
101
126
  rack (>= 0.4)
102
127
  rack-test (1.1.0)
103
128
  rack (>= 1.0, < 3)
104
- rails (5.2.2)
105
- actioncable (= 5.2.2)
106
- actionmailer (= 5.2.2)
107
- actionpack (= 5.2.2)
108
- actionview (= 5.2.2)
109
- activejob (= 5.2.2)
110
- activemodel (= 5.2.2)
111
- activerecord (= 5.2.2)
112
- activestorage (= 5.2.2)
113
- activesupport (= 5.2.2)
129
+ rails (6.0.3.2)
130
+ actioncable (= 6.0.3.2)
131
+ actionmailbox (= 6.0.3.2)
132
+ actionmailer (= 6.0.3.2)
133
+ actionpack (= 6.0.3.2)
134
+ actiontext (= 6.0.3.2)
135
+ actionview (= 6.0.3.2)
136
+ activejob (= 6.0.3.2)
137
+ activemodel (= 6.0.3.2)
138
+ activerecord (= 6.0.3.2)
139
+ activestorage (= 6.0.3.2)
140
+ activesupport (= 6.0.3.2)
114
141
  bundler (>= 1.3.0)
115
- railties (= 5.2.2)
142
+ railties (= 6.0.3.2)
116
143
  sprockets-rails (>= 2.0.0)
117
144
  rails-dom-testing (2.0.3)
118
145
  activesupport (>= 4.2.0)
119
146
  nokogiri (>= 1.6)
120
- rails-html-sanitizer (1.0.4)
121
- loofah (~> 2.2, >= 2.2.2)
122
- railties (5.2.2)
123
- actionpack (= 5.2.2)
124
- activesupport (= 5.2.2)
147
+ rails-html-sanitizer (1.3.0)
148
+ loofah (~> 2.3)
149
+ railties (6.0.3.2)
150
+ actionpack (= 6.0.3.2)
151
+ activesupport (= 6.0.3.2)
125
152
  method_source
126
153
  rake (>= 0.8.7)
127
- thor (>= 0.19.0, < 2.0)
128
- rake (12.3.2)
129
- rspec (3.8.0)
130
- rspec-core (~> 3.8.0)
131
- rspec-expectations (~> 3.8.0)
132
- rspec-mocks (~> 3.8.0)
133
- rspec-core (3.8.0)
134
- rspec-support (~> 3.8.0)
135
- rspec-expectations (3.8.2)
154
+ thor (>= 0.20.3, < 2.0)
155
+ rake (13.0.1)
156
+ rspec (3.9.0)
157
+ rspec-core (~> 3.9.0)
158
+ rspec-expectations (~> 3.9.0)
159
+ rspec-mocks (~> 3.9.0)
160
+ rspec-core (3.9.1)
161
+ rspec-support (~> 3.9.1)
162
+ rspec-expectations (3.9.0)
136
163
  diff-lcs (>= 1.2.0, < 2.0)
137
- rspec-support (~> 3.8.0)
138
- rspec-mocks (3.8.0)
164
+ rspec-support (~> 3.9.0)
165
+ rspec-mocks (3.9.1)
139
166
  diff-lcs (>= 1.2.0, < 2.0)
140
- rspec-support (~> 3.8.0)
141
- rspec-support (3.8.0)
142
- sprockets (3.7.2)
167
+ rspec-support (~> 3.9.0)
168
+ rspec-support (3.9.2)
169
+ ruby2_keywords (0.0.2)
170
+ sprockets (4.0.2)
143
171
  concurrent-ruby (~> 1.0)
144
172
  rack (> 1, < 3)
145
173
  sprockets-rails (3.2.1)
146
174
  actionpack (>= 4.0)
147
175
  activesupport (>= 4.0)
148
176
  sprockets (>= 3.0.0)
149
- thor (0.20.3)
177
+ thor (1.0.1)
150
178
  thread_safe (0.3.6)
151
- tzinfo (1.2.5)
179
+ tzinfo (1.2.7)
152
180
  thread_safe (~> 0.1)
153
- virtus (1.0.5)
154
- axiom-types (~> 0.1)
155
- coercible (~> 1.0)
156
- descendants_tracker (~> 0.0, >= 0.0.3)
157
- equalizer (~> 0.0, >= 0.0.9)
158
- websocket-driver (0.7.0)
181
+ websocket-driver (0.7.2)
159
182
  websocket-extensions (>= 0.1.0)
160
- websocket-extensions (0.1.3)
183
+ websocket-extensions (0.1.5)
184
+ zeitwerk (2.3.0)
161
185
 
162
186
  PLATFORMS
163
187
  ruby
@@ -170,4 +194,4 @@ DEPENDENCIES
170
194
  rspec (~> 3.7)
171
195
 
172
196
  BUNDLED WITH
173
- 1.16.6
197
+ 2.1.2
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![CircleCI](https://circleci.com/gh/EmCousin/grape_fast_jsonapi/tree/master.svg?style=svg)](https://circleci.com/gh/EmCousin/grape_fast_jsonapi/tree/master)
2
+
1
3
  # Grape::FastJsonapi
2
4
 
3
5
  Use [fast_jsonapi](https://github.com/Netflix/fast_jsonapi) with [Grape](https://github.com/ruby-grape/grape).
@@ -17,8 +19,9 @@ gem 'grape_fast_jsonapi'
17
19
 
18
20
  ```ruby
19
21
  class API < Grape::API
20
- format :json
22
+ content_type :jsonapi, "application/vnd.api+json"
21
23
  formatter :json, Grape::Formatter::FastJsonapi
24
+ formatter :jsonapi, Grape::Formatter::FastJsonapi
22
25
  end
23
26
  ```
24
27
 
@@ -31,14 +34,35 @@ get "/" do
31
34
  end
32
35
  ```
33
36
 
37
+ ### Use a custom serializer
38
+
39
+ ```ruby
40
+ get "/" do
41
+ user = User.find("123")
42
+ render user, serializer: 'CustomUserSerializer'
43
+ end
44
+ ```
45
+
46
+ Or
47
+
48
+ ```ruby
49
+ get "/" do
50
+ user = User.find("123")
51
+ render CustomUserSerializer.new(user).serialized_json
52
+ end
53
+ ```
54
+
34
55
  ### Model parser for response documentation
35
56
 
36
57
  When using Grape with Swagger via [grape-swagger](https://github.com/ruby-grape/grape-swagger), you can generate response documentation automatically via the provided following model parser:
37
58
 
38
59
  ```ruby
39
60
  # FastJsonapi serializer example
61
+
62
+ # app/serializers/base_serializer.rb
63
+ class BaseSerializer; end
40
64
  # app/serializers/user_serializer.rb
41
- class UserSerializer
65
+ class UserSerializer < BaseSerializer
42
66
  include FastJsonapi::ObjectSerializer
43
67
 
44
68
  set_type :user
@@ -48,12 +72,13 @@ class UserSerializer
48
72
  end
49
73
 
50
74
  # config/initializers/grape_swagger.rb
51
- GrapeSwagger.model_parsers.register(GrapeSwagger::FastJsonapi::Parser, UserSerializer)
75
+ GrapeSwagger.model_parsers.register(GrapeSwagger::FastJsonapi::Parser, BaseSerializer)
52
76
 
53
77
  # Your grape API endpoint
54
- desc 'Get current user',
55
- success: { code: 200, model: UserSerializer, message: 'The current user' }
78
+ desc 'Get current user' do
79
+ success code: 200, model: UserSerializer, message: 'The current user'
56
80
  # [...]
81
+ end
57
82
  ```
58
83
 
59
84
  Note that you **need** the `grape-swagger` gem for this to work, otherwise it will throw an error.
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails'
4
3
  require 'fast_jsonapi'
5
4
  require 'grape'
6
5
  require 'grape_fast_jsonapi/endpoint_extension'
@@ -36,22 +36,32 @@ module Grape
36
36
  end
37
37
 
38
38
  def fast_jsonapi_serializable(object, options)
39
- serializable_class(object)&.new(object, options)
39
+ serializable_class(object, options)&.new(object, options)
40
40
  end
41
41
 
42
42
  def serializable_collection(collection, options)
43
- if collection.map(&:model_name).uniq.count > 1
43
+ if heterogeneous_collection?(collection)
44
44
  collection.map do |o|
45
45
  fast_jsonapi_serializable(o, options).serializable_hash || o.map(&:serializable_hash)
46
46
  end
47
47
  else
48
- fast_jsonapi_serializable(collection, options).serializable_hash || collection.map(&:serializable_hash)
48
+ fast_jsonapi_serializable(collection, options)&.serializable_hash || collection.map(&:serializable_hash)
49
49
  end
50
50
  end
51
51
 
52
- def serializable_class(object)
53
- object = object.first if object.is_a?(Array)
54
- (object.model_name.name + 'Serializer').safe_constantize
52
+ def heterogeneous_collection?(collection)
53
+ collection.map { |item| item.class.name }.uniq.size > 1
54
+ end
55
+
56
+ def serializable_class(object, options)
57
+ klass_name = options['serializer'] || options[:serializer]
58
+ klass_name ||= begin
59
+ object = object.first if object.is_a?(Array)
60
+
61
+ (object.try(:model_name) || object.class).name + 'Serializer'
62
+ end
63
+
64
+ klass_name&.safe_constantize
55
65
  end
56
66
 
57
67
  def serialize_each_pair(object, env)
@@ -15,18 +15,27 @@ module GrapeSwagger
15
15
  schema = default_schema
16
16
 
17
17
  attributes_hash = if (defined? ActiveRecord)
18
- map_active_record_columns_to_attributes
18
+ map_model_attributes.symbolize_keys.merge(map_active_record_columns_to_attributes.symbolize_keys)
19
19
  else
20
- map_model_attributes
20
+ map_model_attributes.symbolize_keys
21
21
  end
22
22
 
23
23
  attributes_hash.each do |attribute, type|
24
24
  schema[:data][:properties][:attributes][:properties][attribute] = { type: type }
25
- schema[:data][:example][:attributes][attribute] = send "#{type}_example"
25
+ example_method = "#{type}_example"
26
+ unless self.respond_to?(example_method, true)
27
+ puts "WARN unexpected type encountered, missing #{example_method} --use string example instead"
28
+ example_method = "string_example"
29
+ end
30
+ schema[:data][:example][:attributes][attribute] = send example_method
26
31
  end
27
32
 
28
33
  relationships_hash = model.relationships_to_serialize || []
29
34
 
35
+ # If relationship has :key set different than association name, it should be rendered under that key
36
+ relationships_hash =
37
+ relationships_hash.each_with_object({}) { |(_relationship_name, relationship), accu| accu[relationship.key] = relationship }
38
+
30
39
  relationships_hash.each do |model_type, relationship_data|
31
40
  relationships_attributes = relationship_data.instance_values.symbolize_keys
32
41
  schema[:data][:properties][:relationships][:properties][model_type] = {
@@ -36,6 +45,8 @@ module GrapeSwagger
36
45
  schema[:data][:example][:relationships][model_type] = relationships_example(relationships_attributes)
37
46
  end
38
47
 
48
+ schema.deep_merge!(model.additional_schema) if model.respond_to? :additional_schema
49
+
39
50
  schema
40
51
  end
41
52
 
@@ -67,10 +78,10 @@ module GrapeSwagger
67
78
 
68
79
  def map_active_record_columns_to_attributes
69
80
  activerecord_model = model.record_type.to_s.camelize.safe_constantize
70
- return map_model_attributes unless activerecord_model&.is_a?(ActiveRecord::Base)
81
+ return map_model_attributes unless activerecord_model && activerecord_model < ActiveRecord::Base
71
82
 
72
83
  columns = activerecord_model.columns.select do |c|
73
- c.name.to_sym.in?(model.attributes_to_serialize.keys)
84
+ model.attributes_to_serialize.keys.include?(c.name.to_sym)
74
85
  end
75
86
 
76
87
  attributes = {}
@@ -83,8 +94,13 @@ module GrapeSwagger
83
94
 
84
95
  def map_model_attributes
85
96
  attributes = {}
86
- model.attributes_to_serialize.each do |attribute, _|
87
- attributes[attribute] = :string
97
+ (model.attributes_to_serialize || []).each do |attribute, _|
98
+ attributes[attribute] =
99
+ if model.respond_to? :attribute_types
100
+ model.attribute_types[attribute] || :string
101
+ else
102
+ :string
103
+ end
88
104
  end
89
105
  attributes
90
106
  end
@@ -147,6 +163,14 @@ module GrapeSwagger
147
163
  end
148
164
  end
149
165
 
166
+ def citext_example
167
+ text_example
168
+ end
169
+
170
+ def float_example
171
+ rand() * rand(1..100)
172
+ end
173
+
150
174
  def date_example
151
175
  Date.today.to_s
152
176
  end
@@ -173,6 +197,10 @@ module GrapeSwagger
173
197
  def boolean_example
174
198
  [true, false].sample
175
199
  end
200
+
201
+ def uuid_example
202
+ SecureRandom.uuid
203
+ end
176
204
  end
177
205
  end
178
- end
206
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Grape
4
4
  module FastJsonapi
5
- VERSION = '0.2.0'.freeze
5
+ VERSION = '0.2.6'.freeze
6
6
  end
7
7
  end
@@ -11,10 +11,14 @@ describe Grape::Formatter::FastJsonapi do
11
11
  let(:blog_post) do
12
12
  BlogPost.new(id: 1, title: "Blog Post title", body: "Blog post body")
13
13
  end
14
+ let(:admin) do
15
+ UserAdmin.new(id: 1, first_name: 'Jean Luc', last_name: 'Picard', password: 'supersecretpassword', email: 'jeanluc@picard.com')
16
+ end
14
17
 
15
18
  describe '.call' do
16
19
  subject { described_class.call(object, env) }
17
- let(:env) { {} }
20
+ let(:fast_jsonapi_options) { nil }
21
+ let(:env) { { 'fast_jsonapi_options' => fast_jsonapi_options } }
18
22
 
19
23
  context 'when the object is a string' do
20
24
  let(:object) { "I am a string" }
@@ -24,8 +28,14 @@ describe Grape::Formatter::FastJsonapi do
24
28
 
25
29
  context 'when the object is serializable' do
26
30
  let(:user_serializer) { UserSerializer.new(object, {}) }
31
+ let(:another_user_serializer) { AnotherUserSerializer.new(object, {}) }
27
32
  let(:blog_post_serializer) { BlogPostSerializer.new(object, {}) }
28
33
 
34
+ context 'when the object has a model_name defined' do
35
+ let(:object) { admin }
36
+ it { is_expected.to eq ::Grape::Json.dump(user_serializer.serializable_hash) }
37
+ end
38
+
29
39
  context 'when the object is a active serializable model instance' do
30
40
  let(:object) { user }
31
41
 
@@ -36,19 +46,31 @@ describe Grape::Formatter::FastJsonapi do
36
46
  let(:object) { [user, another_user] }
37
47
 
38
48
  it { is_expected.to eq ::Grape::Json.dump(user_serializer.serializable_hash) }
49
+ end
39
50
 
40
- context "when the array contains instances of different models" do
41
- let(:object) { [user, blog_post] }
51
+ context "when the array contains instances of different models" do
52
+ let(:object) { [user, blog_post] }
42
53
 
43
- it 'returns an array of jsonapi serialialized objects' do
44
- expect(subject).to eq(::Grape::Json.dump([
45
- UserSerializer.new(user, {}).serializable_hash,
46
- BlogPostSerializer.new(blog_post, {}).serializable_hash
47
- ]))
48
- end
54
+ it 'returns an array of jsonapi serialialized objects' do
55
+ expect(subject).to eq(::Grape::Json.dump([
56
+ UserSerializer.new(user, {}).serializable_hash,
57
+ BlogPostSerializer.new(blog_post, {}).serializable_hash
58
+ ]))
49
59
  end
50
60
  end
51
61
 
62
+ context 'when the object is an empty array ' do
63
+ let(:object) { [] }
64
+
65
+ it { is_expected.to eq ::Grape::Json.dump(object) }
66
+ end
67
+
68
+ context 'when the object is an array of null objects ' do
69
+ let(:object) { [nil, nil] }
70
+
71
+ it { is_expected.to eq ::Grape::Json.dump(object) }
72
+ end
73
+
52
74
  context 'when the object is a Hash of plain values' do
53
75
  let(:object) { user.as_json }
54
76
 
@@ -82,6 +104,15 @@ describe Grape::Formatter::FastJsonapi do
82
104
 
83
105
  it { is_expected.to eq '42' }
84
106
  end
107
+
108
+ context 'when a custom serializer is passed as an option' do
109
+ let(:object) { user }
110
+ let(:fast_jsonapi_options) { {
111
+ 'serializer' => '::AnotherUserSerializer'
112
+ } }
113
+
114
+ it { is_expected.to eq ::Grape::Json.dump(another_user_serializer.serializable_hash) }
115
+ end
85
116
  end
86
117
  end
87
118
  end
@@ -126,6 +126,89 @@ describe GrapeSwagger::FastJsonapi::Parser do
126
126
  })
127
127
  end
128
128
  end
129
+
130
+ context 'when schema has an association with :key different than association name' do
131
+ let(:model) { FooSerializer }
132
+
133
+ it 'includes associations as defined by :key attributes' do
134
+ expect(subject[:data][:properties][:relationships][:properties]).to include(:foo_bar, :foo_fizz, :foo_buzzes)
135
+ end
136
+ end
137
+
138
+ context 'when serializer has additional schema specified' do
139
+ let(:model) { FooSerializer }
140
+
141
+ it 'is deep-merged into the returned schema' do
142
+ expect(subject[:data][:example][:attributes]).to include(xyz: 'foobar')
143
+ end
144
+ end
145
+
146
+ context 'when serializer has DB-backed model' do
147
+ let(:model) { DbRecordSerializer }
148
+
149
+ before { allow(SecureRandom).to receive(:uuid).and_return 'fakeuuid' }
150
+
151
+ it 'contains examples for corresponding data types' do
152
+ expect(subject[:data][:example][:attributes]).to include(
153
+ string_attribute: be_a(String),
154
+ uuid_attribute: 'fakeuuid',
155
+ integer_attribute: be_a(Integer),
156
+ text_attribute: be_a(String),
157
+ datetime_attribute: satisfy { |val| Time.parse(val).is_a? Time },
158
+ date_attribute: satisfy { |val| Date.parse(val).is_a? Date },
159
+ boolean_attribute: be_a(TrueClass).or(be_a(FalseClass)),
160
+ array_attribute: be_a(Array)
161
+ )
162
+ end
163
+ end
164
+
165
+ context 'when the serializer doesn\'t have any attributes' do
166
+ let(:model) { AnotherBlogPostSerializer } # no attributes
167
+
168
+ it 'return a hash defining the schema with empty attributes' do
169
+ expect(subject).to eq({
170
+ data: {
171
+ type: :object,
172
+ properties: {
173
+ id: { type: :integer },
174
+ type: { type: :string },
175
+ attributes: {
176
+ type: :object,
177
+ properties: {}
178
+ },
179
+ relationships: {
180
+ type: :object,
181
+ properties: {
182
+ user: {
183
+ properties: {
184
+ data: {
185
+ properties: {
186
+ id: { type: :integer },
187
+ type: { type: :string }
188
+ },
189
+ type: :object,
190
+ }
191
+ },
192
+ type: :object,
193
+ }
194
+ }
195
+ }
196
+ },
197
+ example: {
198
+ id: 1,
199
+ type: :blog_post,
200
+ attributes: {
201
+ },
202
+ relationships: {
203
+ user: {
204
+ data: { id: 1, type: :user }
205
+ }
206
+ }
207
+ }
208
+ }
209
+ })
210
+ end
211
+ end
129
212
  end
130
213
  end
131
- end
214
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe Grape::FastJsonapi::VERSION do
4
- it { is_expected.to eq '0.2.0' }
4
+ it { is_expected.to eq '0.2.6' }
5
5
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class BlogPost
4
- extend ActiveModel::Naming
5
4
  include ActiveModel::Serialization
6
5
 
7
6
  attr_accessor :id, :title, :body
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ require 'active_record'
3
+
4
+ class DbRecord < ActiveRecord::Base
5
+ def self.columns
6
+ [
7
+ # adhering to the ActiveRecord::ConnectionAdapters::Column contract
8
+ OpenStruct.new(name: 'id', sql_type: 'integer', type: :integer),
9
+ OpenStruct.new(name: 'string_attribute', sql_type: 'character varying(255)', type: :string),
10
+ OpenStruct.new(name: 'uuid_attribute', sql_type: 'uuid', type: :uuid),
11
+ OpenStruct.new(name: 'integer_attribute', sql_type: 'integer', type: :integer),
12
+ OpenStruct.new(name: 'text_attribute', sql_type: 'text', type: :text),
13
+ OpenStruct.new(name: 'datetime_attribute', sql_type: 'timestamp without time zone', type: :datetime),
14
+ OpenStruct.new(name: 'date_attribute', sql_type: 'date', type: :date),
15
+ OpenStruct.new(name: 'boolean_attribute', sql_type: 'boolean', type: :boolean),
16
+ OpenStruct.new(name: 'array_attribute', sql_type: 'integer[]', type: :array)
17
+ ]
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Foo
4
+ include ActiveModel::Serialization
5
+
6
+ attr_accessor :id, :bar_id
7
+
8
+ # belongs_to :bar
9
+ # has_one :fizz
10
+ # has_many :buzzes
11
+
12
+ def initialize(params = {})
13
+ params.each do |k, v|
14
+ instance_variable_set("@#{k}", v) unless v.nil?
15
+ end
16
+ end
17
+
18
+ def attributes
19
+ {
20
+ 'id' => nil,
21
+ 'bar_id' => nil
22
+ }
23
+ end
24
+
25
+ def buzz_ids
26
+ []
27
+ end
28
+ end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class User
4
- extend ActiveModel::Naming
5
4
  include ActiveModel::Serialization
6
5
 
7
6
  attr_accessor :id, :first_name, :last_name, :password, :email
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UserAdmin
4
+ include ActiveModel::Serialization
5
+
6
+ attr_accessor :id, :first_name, :last_name, :password, :email
7
+
8
+ def initialize(params = {})
9
+ params.each do |k, v|
10
+ instance_variable_set("@#{k}", v) unless v.nil?
11
+ end
12
+ end
13
+
14
+ def attributes
15
+ {
16
+ 'id' => nil,
17
+ 'first_name' => nil,
18
+ 'last_name' => nil,
19
+ 'password' => nil,
20
+ 'email' => nil
21
+ }
22
+ end
23
+
24
+ def blog_post_ids
25
+ []
26
+ end
27
+
28
+ def model_name
29
+ ActiveModel::Name.new(User)
30
+ end
31
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AnotherBlogPostSerializer
4
+ include FastJsonapi::ObjectSerializer
5
+
6
+ set_type :blog_post
7
+
8
+ belongs_to :user
9
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AnotherUserSerializer
4
+ include FastJsonapi::ObjectSerializer
5
+
6
+ attributes :email
7
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record'
4
+
5
+ class DbRecordSerializer
6
+ include FastJsonapi::ObjectSerializer
7
+
8
+ attributes(
9
+ :string_attribute,
10
+ :uuid_attribute,
11
+ :integer_attribute,
12
+ :text_attribute,
13
+ :datetime_attribute,
14
+ :date_attribute,
15
+ :boolean_attribute,
16
+ :array_attribute
17
+ )
18
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FooSerializer
4
+ include FastJsonapi::ObjectSerializer
5
+
6
+ belongs_to :bar, key: :foo_bar
7
+ has_one :fizz, key: :foo_fizz
8
+ has_many :buzzes, key: :foo_buzzes
9
+
10
+ attribute :xyz
11
+
12
+ def self.additional_schema
13
+ {
14
+ data: {
15
+ example: {
16
+ attributes: {
17
+ xyz: 'foobar'
18
+ }
19
+ }
20
+ }
21
+ }
22
+ end
23
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape_fast_jsonapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emmanuel Cousin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-04 00:00:00.000000000 Z
11
+ date: 2020-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: grape
@@ -93,8 +93,15 @@ files:
93
93
  - spec/lib/grape_fast_jsonapi/version_spec.rb
94
94
  - spec/spec_helper.rb
95
95
  - spec/support/models/blog_post.rb
96
+ - spec/support/models/db_record.rb
97
+ - spec/support/models/foo.rb
96
98
  - spec/support/models/user.rb
99
+ - spec/support/models/user_admin.rb
100
+ - spec/support/serializers/another_blog_post_serializer.rb
101
+ - spec/support/serializers/another_user_serializer.rb
97
102
  - spec/support/serializers/blog_post_serializer.rb
103
+ - spec/support/serializers/db_record_serializer.rb
104
+ - spec/support/serializers/foo_serializer.rb
98
105
  - spec/support/serializers/user_serializer.rb
99
106
  homepage: https://github.com/EmCousin/grape_fast_jsonapi
100
107
  licenses:
@@ -115,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
122
  - !ruby/object:Gem::Version
116
123
  version: '0'
117
124
  requirements: []
118
- rubygems_version: 3.0.1
125
+ rubygems_version: 3.1.2
119
126
  signing_key:
120
127
  specification_version: 4
121
128
  summary: Use fast_jsonapi in grape
@@ -125,6 +132,13 @@ test_files:
125
132
  - spec/lib/grape_fast_jsonapi/version_spec.rb
126
133
  - spec/spec_helper.rb
127
134
  - spec/support/models/blog_post.rb
135
+ - spec/support/models/db_record.rb
136
+ - spec/support/models/foo.rb
128
137
  - spec/support/models/user.rb
138
+ - spec/support/models/user_admin.rb
139
+ - spec/support/serializers/another_blog_post_serializer.rb
140
+ - spec/support/serializers/another_user_serializer.rb
129
141
  - spec/support/serializers/blog_post_serializer.rb
142
+ - spec/support/serializers/db_record_serializer.rb
143
+ - spec/support/serializers/foo_serializer.rb
130
144
  - spec/support/serializers/user_serializer.rb