grape_fast_jsonapi 0.2.0 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
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