alba 1.1.0 → 1.5.0
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/.github/ISSUE_TEMPLATE/bug_report.md +26 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/dependabot.yml +26 -0
- data/.github/workflows/perf.yml +21 -0
- data/.rubocop.yml +18 -8
- data/.yardopts +2 -0
- data/CHANGELOG.md +40 -0
- data/Gemfile +4 -3
- data/README.md +377 -14
- data/SECURITY.md +12 -0
- data/alba.gemspec +2 -2
- data/benchmark/collection.rb +441 -0
- data/benchmark/{local.rb → single_resource.rb} +120 -15
- data/codecov.yml +3 -0
- data/docs/migrate_from_active_model_serializers.md +359 -0
- data/docs/migrate_from_jbuilder.md +223 -0
- data/gemfiles/all.gemfile +1 -1
- data/gemfiles/without_active_support.gemfile +1 -1
- data/gemfiles/without_oj.gemfile +1 -1
- data/lib/alba/association.rb +14 -17
- data/lib/alba/default_inflector.rb +36 -0
- data/lib/alba/deprecation.rb +14 -0
- data/lib/alba/key_transform_factory.rb +33 -0
- data/lib/alba/many.rb +1 -1
- data/lib/alba/resource.rb +226 -83
- data/lib/alba/typed_attribute.rb +61 -0
- data/lib/alba/version.rb +1 -1
- data/lib/alba.rb +82 -21
- data/script/perf_check.rb +174 -0
- data/sider.yml +2 -4
- metadata +20 -9
- data/lib/alba/key_transformer.rb +0 -32
@@ -0,0 +1,359 @@
|
|
1
|
+
---
|
2
|
+
title: Upgrading from ActiveModelSerializers
|
3
|
+
---
|
4
|
+
|
5
|
+
<!-- @format -->
|
6
|
+
|
7
|
+
This guide is aimed at helping ActiveModelSerializers users transition to Alba, and it consists of three parts:
|
8
|
+
|
9
|
+
1. Basic serialization
|
10
|
+
2. Complex serialization
|
11
|
+
3. Unsupported features
|
12
|
+
|
13
|
+
## Example class
|
14
|
+
|
15
|
+
Example clsss is inherited `ActiveRecord::Base`, because [serializing PORO with AMS is pretty hard](https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/howto/serialize_poro.md).
|
16
|
+
|
17
|
+
```rb
|
18
|
+
class User < ActiveRecord::Base
|
19
|
+
# columns: id, created_at, updated_at
|
20
|
+
has_one :profile
|
21
|
+
has_many :articles
|
22
|
+
end
|
23
|
+
|
24
|
+
class Profile < ActiveRecord::Base
|
25
|
+
# columns: id, user_id, email, created_at, updated_at
|
26
|
+
belongs_to :user
|
27
|
+
end
|
28
|
+
|
29
|
+
class Article < ActiveRecord::Base
|
30
|
+
# columns: id, user_id, title, body, created_at, updated_at
|
31
|
+
belongs_to :user
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
## 1. Basic serialization
|
36
|
+
|
37
|
+
### #serializable_hash
|
38
|
+
|
39
|
+
- or #as_json, #to_json
|
40
|
+
|
41
|
+
#### ActiveModelSerializer
|
42
|
+
|
43
|
+
```rb
|
44
|
+
# Infer and use by "#{MODEL_NAME}Serializer" in app/serializers/user_serializer.rb
|
45
|
+
class UserSerializer < ActiveModel::Serializer
|
46
|
+
type :user
|
47
|
+
attributes :id, :created_at, :updated_at
|
48
|
+
end
|
49
|
+
|
50
|
+
# serialze
|
51
|
+
user = User.create!
|
52
|
+
ActiveModelSerializers::SerializableResource.new(
|
53
|
+
user
|
54
|
+
).serializable_hash
|
55
|
+
# => {
|
56
|
+
# user: {
|
57
|
+
# id: id,
|
58
|
+
# created_at: created_at,
|
59
|
+
# updated_at: updated_at
|
60
|
+
# }
|
61
|
+
# }
|
62
|
+
```
|
63
|
+
|
64
|
+
#### Alba
|
65
|
+
|
66
|
+
```rb
|
67
|
+
# Infer and use by "#{MODEL_NAME}Resource"
|
68
|
+
# In app/resources/user_resource.rb
|
69
|
+
class UserResource
|
70
|
+
include Alba::Resource
|
71
|
+
attributes :id, :created_at, :updated_at
|
72
|
+
end
|
73
|
+
|
74
|
+
# serialze
|
75
|
+
user = User.create!
|
76
|
+
UserResource.new(user).serializable_hash
|
77
|
+
# => {
|
78
|
+
# id: id,
|
79
|
+
# created_at: created_at,
|
80
|
+
# updated_at: updated_at,
|
81
|
+
# }
|
82
|
+
|
83
|
+
# If want `user key`
|
84
|
+
class UserResource
|
85
|
+
include Alba::Resource
|
86
|
+
root_key :user # Call root_key method like ActiveModel::Serializer#type
|
87
|
+
attributes :id, :created_at, :updated_at
|
88
|
+
end
|
89
|
+
|
90
|
+
# serialze
|
91
|
+
user = User.create!
|
92
|
+
JSON.parse UserResource.new(user).serialize # !!!!serializable_hash does not support root key!!! Must use JSON.parse and serialize
|
93
|
+
# => {
|
94
|
+
# "user"=>{
|
95
|
+
# "id"=>id,
|
96
|
+
# "created_at"=>created_at,
|
97
|
+
# "updated_at"=>updated_at
|
98
|
+
# }
|
99
|
+
# }
|
100
|
+
# If want symbolize keys with #deep_symbolize_keys in Rails
|
101
|
+
user = User.create!
|
102
|
+
JSON.parse(UserResource.new(user).serialize).deep_symbolize_keys
|
103
|
+
# => {
|
104
|
+
# user: {
|
105
|
+
# id: id,
|
106
|
+
# created_at: created_at,
|
107
|
+
# updated_at: updated_at
|
108
|
+
# }
|
109
|
+
# }
|
110
|
+
```
|
111
|
+
|
112
|
+
## 2. Complex serialization
|
113
|
+
|
114
|
+
### Serialize collections
|
115
|
+
|
116
|
+
#### ActiveModelSerializer
|
117
|
+
|
118
|
+
```rb
|
119
|
+
class UserSerializer < ActiveModel::Serializer
|
120
|
+
type :user
|
121
|
+
attributes :id, :created_at, :updated_at
|
122
|
+
end
|
123
|
+
3.times { User.create! }
|
124
|
+
users = User.limit 3
|
125
|
+
ActiveModelSerializers::SerializableResource.new(
|
126
|
+
users,
|
127
|
+
adapter: :attributes # Comment out this line if you want users key
|
128
|
+
# Want to specified key to call with root: args
|
129
|
+
).serializable_hash
|
130
|
+
# => [{:id=>1, :created_at=>created_at, :updated_at=>updated_at},
|
131
|
+
# {:id=>2, :created_at=>created_at, :updated_at=>updated_at},
|
132
|
+
# {:id=>3, :created_at=>created_at, :updated_at=>updated_at}]
|
133
|
+
```
|
134
|
+
|
135
|
+
#### Alba
|
136
|
+
|
137
|
+
```rb
|
138
|
+
class UserResource
|
139
|
+
include Alba::Resource
|
140
|
+
attributes :id, :created_at, :updated_at
|
141
|
+
end
|
142
|
+
3.times { User.create! }
|
143
|
+
users = User.limit 3
|
144
|
+
UserResource.new(users).serializable_hash
|
145
|
+
# =>[{:id=>1, :created_at=>created_at, :updated_at=>updated_at},
|
146
|
+
# {:id=>2, :created_at=>created_at, :updated_at=>updated_at},
|
147
|
+
# {:id=>3, :created_at=>created_at, :updated_at=>updated_at}]
|
148
|
+
# or
|
149
|
+
JSON.parse UserResource.new(users).serialize(root_key: :users)
|
150
|
+
# => {"users"=>
|
151
|
+
# [{"id"=>1, "created_at"=>created_at, "updated_at"=>updated_at},
|
152
|
+
# {"id"=>2, "created_at"=>created_at, "updated_at"=>updated_at},
|
153
|
+
# {"id"=>3, "created_at"=>created_at, "updated_at"=>updated_at}]}
|
154
|
+
```
|
155
|
+
|
156
|
+
### Nested serialization
|
157
|
+
|
158
|
+
#### ActiveModelSerializer
|
159
|
+
|
160
|
+
```rb
|
161
|
+
class ProfileSerializer < ActiveModel::Serializer
|
162
|
+
type :profile
|
163
|
+
attributes :email
|
164
|
+
end
|
165
|
+
|
166
|
+
class ArticleSerializer < ActiveModel::Serializer
|
167
|
+
type :article
|
168
|
+
attributes :title, :body
|
169
|
+
end
|
170
|
+
|
171
|
+
class UserSerializer < ActiveModel::Serializer
|
172
|
+
type :user
|
173
|
+
attributes :id, :created_at, :updated_at
|
174
|
+
has_one :profile, serializer: ProfileSerializer # For has_one relation
|
175
|
+
has_many :articles, serializer: ArticleSerializer # For has_many relation
|
176
|
+
end
|
177
|
+
user = User.create!
|
178
|
+
user.craete_profile! email: email
|
179
|
+
user.articles.create! title: title, body: body
|
180
|
+
ActiveModelSerializers::SerializableResource.new(
|
181
|
+
user
|
182
|
+
).serializable_hash
|
183
|
+
# => {
|
184
|
+
# :user=> {
|
185
|
+
# :id=>1,
|
186
|
+
# :created_at=>created_at,
|
187
|
+
# :updated_at=>updated_at,
|
188
|
+
# :profile=> {
|
189
|
+
# :email=>email
|
190
|
+
# },
|
191
|
+
# :articles => [
|
192
|
+
# {
|
193
|
+
# :title=>title,
|
194
|
+
# :body=>body
|
195
|
+
# }
|
196
|
+
# ]
|
197
|
+
# }
|
198
|
+
# }
|
199
|
+
```
|
200
|
+
|
201
|
+
#### Alba
|
202
|
+
|
203
|
+
```rb
|
204
|
+
class ProfileResource
|
205
|
+
include Alba::Resource
|
206
|
+
root_key :profile
|
207
|
+
attributes :email
|
208
|
+
end
|
209
|
+
|
210
|
+
class ArticleResource
|
211
|
+
include Alba::Resource
|
212
|
+
root_key :article
|
213
|
+
attributes :title, :body
|
214
|
+
end
|
215
|
+
|
216
|
+
class UserResource
|
217
|
+
include Alba::Resource
|
218
|
+
root_key :user
|
219
|
+
attributes :id, :created_at, :updated_at
|
220
|
+
one :profile, resource: ProfileResource # For has_one relation
|
221
|
+
many :articles, resource: ArticleResource # For has_many relation
|
222
|
+
end
|
223
|
+
|
224
|
+
user = User.create!
|
225
|
+
user.craete_profile! email: email
|
226
|
+
user.articles.create! title: title, body: body
|
227
|
+
UserResource.new(user).serializable_hash
|
228
|
+
# => {
|
229
|
+
# :id=>1,
|
230
|
+
# :created_at=>created_at,
|
231
|
+
# :updated_at=>updated_at,
|
232
|
+
# :profile=> {
|
233
|
+
# :email=>email
|
234
|
+
# },
|
235
|
+
# :articles => [
|
236
|
+
# {
|
237
|
+
# :title=>title,
|
238
|
+
# :body=>body
|
239
|
+
# }
|
240
|
+
# ]
|
241
|
+
# }
|
242
|
+
```
|
243
|
+
|
244
|
+
### Serialize with custom serializer
|
245
|
+
|
246
|
+
#### ActiveModelSerializer
|
247
|
+
|
248
|
+
```rb
|
249
|
+
class CustomUserSerializer < ActiveModel::Serializer
|
250
|
+
type :user
|
251
|
+
attribute :email do
|
252
|
+
object.profile.email
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
# serialze
|
257
|
+
user = User.create!
|
258
|
+
user.craete_profile! email: email
|
259
|
+
ActiveModelSerializers::SerializableResource.new(
|
260
|
+
user,
|
261
|
+
serializer: ::CustomUserSerializer # Call with serializer arg
|
262
|
+
).serializable_hash
|
263
|
+
# => {
|
264
|
+
# user: {
|
265
|
+
# email: email
|
266
|
+
# }
|
267
|
+
# }
|
268
|
+
```
|
269
|
+
|
270
|
+
#### Alba
|
271
|
+
|
272
|
+
```rb
|
273
|
+
class CustomUserResource
|
274
|
+
include Alba::Resource
|
275
|
+
root_key :user
|
276
|
+
attribute :email do
|
277
|
+
object.profile.email
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# serialze
|
282
|
+
user = User.create!
|
283
|
+
user.craete_profile! email: email
|
284
|
+
CustomUserResource.new(user).serializable_hash
|
285
|
+
# => {
|
286
|
+
# email: email
|
287
|
+
# }
|
288
|
+
```
|
289
|
+
|
290
|
+
### Passing arbitrary options to a serializer
|
291
|
+
|
292
|
+
#### ActiveModelSerializer
|
293
|
+
|
294
|
+
```rb
|
295
|
+
class UserSerializer < ApplicationSerializer
|
296
|
+
type :user
|
297
|
+
attributes :id, :created_at, :updated_at
|
298
|
+
attribute :custom_params do
|
299
|
+
pp instance_options
|
300
|
+
# => given_params: { a: :b }
|
301
|
+
instance_options # Access by instance_options method
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
# serialze
|
306
|
+
user = User.create!
|
307
|
+
ActiveModelSerializers::SerializableResource.new(
|
308
|
+
user,
|
309
|
+
given_params: { a: :b } # Give with your favorite keyword argument
|
310
|
+
).serializable_hash
|
311
|
+
# => {
|
312
|
+
# :id=>1,
|
313
|
+
# :created_at=>created_at,
|
314
|
+
# :updated_at=>updated_at,
|
315
|
+
# :custom_params=>{
|
316
|
+
# :given_params=>{
|
317
|
+
# :a=>:b
|
318
|
+
# }
|
319
|
+
# }
|
320
|
+
# }
|
321
|
+
```
|
322
|
+
|
323
|
+
#### Alba
|
324
|
+
|
325
|
+
```rb
|
326
|
+
class UserResource
|
327
|
+
include Alba::Resource
|
328
|
+
root_key :user
|
329
|
+
attributes :id, :created_at, :updated_at
|
330
|
+
attribute :custom_params do
|
331
|
+
pp params
|
332
|
+
# => { :a=>:b }
|
333
|
+
params
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
# serialze
|
338
|
+
user = User.create!
|
339
|
+
UserResource.new(
|
340
|
+
user,
|
341
|
+
params: { a: :b } # Give with :params keyword argument
|
342
|
+
).serializable_hash
|
343
|
+
# => {
|
344
|
+
# :id=>1,
|
345
|
+
# :created_at=>created_at,
|
346
|
+
# :updated_at=>updated_at,
|
347
|
+
# :custom_params=>{
|
348
|
+
# :a=>:b
|
349
|
+
# }
|
350
|
+
# }
|
351
|
+
```
|
352
|
+
|
353
|
+
## 3. Unsupported features
|
354
|
+
|
355
|
+
- [RelationshipLinks](https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/howto/add_relationship_links.md)
|
356
|
+
- [PaginationLinks](https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/howto/add_pagination_links.md)
|
357
|
+
- [Logging](https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/logging.md)
|
358
|
+
- [Caching](https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/caching.md)
|
359
|
+
- [Rendering](https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/rendering.md)
|
@@ -0,0 +1,223 @@
|
|
1
|
+
---
|
2
|
+
title: Upgrading from Jbuilder
|
3
|
+
---
|
4
|
+
|
5
|
+
<!-- @format -->
|
6
|
+
|
7
|
+
This guide is aimed at helping Jbuilder users transition to Alba, and it consists of three parts:
|
8
|
+
|
9
|
+
1. Basic serialization
|
10
|
+
2. Complex serialization
|
11
|
+
3. Unsupported features
|
12
|
+
|
13
|
+
## Example class
|
14
|
+
|
15
|
+
This example will also be replaced by ActiveReord.
|
16
|
+
|
17
|
+
```rb
|
18
|
+
class User
|
19
|
+
attr_reader :id, :created_at, :updated_at
|
20
|
+
attr_accessor :profile, :articles
|
21
|
+
|
22
|
+
def initialize(id)
|
23
|
+
@id = id
|
24
|
+
@created_at = Time.now
|
25
|
+
@updated_at = Time.now
|
26
|
+
@articles = []
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Profile
|
31
|
+
attr_reader :email
|
32
|
+
|
33
|
+
def initialize(email)
|
34
|
+
@email = email
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Article
|
39
|
+
attr_accessor :title, :body
|
40
|
+
|
41
|
+
def initialize(title, body)
|
42
|
+
@title = title
|
43
|
+
@body = body
|
44
|
+
end
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
## 1. Basic serialization
|
49
|
+
|
50
|
+
#### Jbuilder
|
51
|
+
|
52
|
+
```rb
|
53
|
+
# show.json.jbuilder
|
54
|
+
# With block
|
55
|
+
@user = User.new(id)
|
56
|
+
json.user do |user|
|
57
|
+
user.id @user.id
|
58
|
+
user.created_at @user.created_at
|
59
|
+
user.updated_at @user.updated_at
|
60
|
+
end
|
61
|
+
# => '{"user":{"id":id, "created_at": created_at, "updated_at": updated_at}'
|
62
|
+
# or #extract!
|
63
|
+
json.extract! @user, :id, :created_at, :updated_at
|
64
|
+
# => '{"id":id, "created_at": created_at, "updated_at": updated_at}'
|
65
|
+
```
|
66
|
+
|
67
|
+
#### Alba
|
68
|
+
|
69
|
+
```rb
|
70
|
+
# With block
|
71
|
+
user = User.new(id)
|
72
|
+
Alba.serialize(user, root_key: :user) do
|
73
|
+
attributes :id, :created_at, :updated_at
|
74
|
+
end
|
75
|
+
# => '{"user":{"id":id, "created_at": created_at, "updated_at": updated_at}'
|
76
|
+
# or with resourceClass.
|
77
|
+
# Infer and use by "#{MODEL_NAME}Resource"
|
78
|
+
class UserResource
|
79
|
+
include Alba::Resource
|
80
|
+
root_key :user
|
81
|
+
attributes :id, :created_at, :updated_at
|
82
|
+
end
|
83
|
+
UserResource.new(user).serialize
|
84
|
+
# => '{"user":{"id":id, "created_at": created_at, "updated_at": updated_at}'
|
85
|
+
```
|
86
|
+
|
87
|
+
## 2. Complex serialization
|
88
|
+
|
89
|
+
### Serialize collections
|
90
|
+
|
91
|
+
#### Jbuilder
|
92
|
+
|
93
|
+
```rb
|
94
|
+
@users = ids.map { |id| User.new(id) }
|
95
|
+
# index.json.jbuilder
|
96
|
+
json.array! @users, :id, :created_at, :updated_at
|
97
|
+
# => '[{"id":id, "created_at": created_at, "updated_at": updated_at}, {"id":id, "created_at": created_at, "updated_at": updated_at}, {"id":id, "created_at": created_at, "updated_at": updated_at}]'
|
98
|
+
```
|
99
|
+
|
100
|
+
#### Alba
|
101
|
+
|
102
|
+
```rb
|
103
|
+
class UserResource
|
104
|
+
include Alba::Resource
|
105
|
+
root_key :user
|
106
|
+
attributes :id, :created_at, :updated_at
|
107
|
+
end
|
108
|
+
users = ids.map { |id| User.new(id) }
|
109
|
+
UserResource.new(users).serialize
|
110
|
+
# => '[{"id":id, "created_at": created_at, "updated_at": updated_at}, {"id":id, "created_at": created_at, "updated_at": updated_at}, {"id":id, "created_at": created_at, "updated_at": updated_at}]'
|
111
|
+
|
112
|
+
```
|
113
|
+
|
114
|
+
### Nested serialization
|
115
|
+
|
116
|
+
#### Jbuilder
|
117
|
+
|
118
|
+
```rb
|
119
|
+
# show.json.jbuilder
|
120
|
+
@user = User.new(id)
|
121
|
+
@user.profile = Profile.new(email)
|
122
|
+
@user.articles = [Article.new(title, body)]
|
123
|
+
json.user do |user|
|
124
|
+
user.id @user.id
|
125
|
+
user.created_at @user.created_at
|
126
|
+
user.updated_at @user.updated_at
|
127
|
+
json.profile do
|
128
|
+
json.email @user.profile.email
|
129
|
+
end
|
130
|
+
json.articles do
|
131
|
+
json.array! @user.articles, :title, :body
|
132
|
+
end
|
133
|
+
end
|
134
|
+
# => '{"user":{"id":id, "created_at": created_at, "updated_at": updated_at, "profile": {"email": email}, articles: [{"title": title, "body": body}]}'
|
135
|
+
# or #merge!
|
136
|
+
profile_hash = { profile: { email: @user.profile.email } }
|
137
|
+
articles_hash = { articles: @user.articles.map { |article| { title: article.title, body: article.body } } }
|
138
|
+
json.user do |user|
|
139
|
+
user.id @user.id
|
140
|
+
user.created_at @user.created_at
|
141
|
+
user.updated_at @user.updated_at
|
142
|
+
json.merge! profile_hash
|
143
|
+
json.merge! articles_hash
|
144
|
+
end
|
145
|
+
# => '{"user":{"id":id, "created_at": created_at, "updated_at": updated_at, "profile": {"email": email}, articles: [{"title": title, "body": body}]}'
|
146
|
+
# or #partial!
|
147
|
+
# profiles/_profile.json.jbuilder
|
148
|
+
json.profile do
|
149
|
+
json.email @profile.email
|
150
|
+
end
|
151
|
+
# articles/_article.json.jbuilder
|
152
|
+
json.extract! article, :title, :body
|
153
|
+
# user/show.json.jbuilder
|
154
|
+
json.user do |user|
|
155
|
+
user.id @user.id
|
156
|
+
user.created_at @user.created_at
|
157
|
+
user.updated_at @user.updated_at
|
158
|
+
json.partial! @user.profile, as: :profile
|
159
|
+
json.articles @user.articles do |article|
|
160
|
+
json.partial! article, partial: 'articles/article'
|
161
|
+
end
|
162
|
+
end
|
163
|
+
```
|
164
|
+
|
165
|
+
#### Alba
|
166
|
+
|
167
|
+
```rb
|
168
|
+
# With ResourceClass by each resources
|
169
|
+
class ProfileResource
|
170
|
+
include Alba::Resource
|
171
|
+
root_key :profile
|
172
|
+
attributes :email
|
173
|
+
end
|
174
|
+
class ArticleResource
|
175
|
+
include Alba::Resource
|
176
|
+
root_key :article
|
177
|
+
attributes :title, :body
|
178
|
+
end
|
179
|
+
class UserResource
|
180
|
+
include Alba::Resource
|
181
|
+
root_key :user
|
182
|
+
attributes :id, :created_at, :updated_at
|
183
|
+
one :profile, resource: ProfileResource
|
184
|
+
many :articles, resource: ArticleResource
|
185
|
+
end
|
186
|
+
user = User.new(id)
|
187
|
+
user.profile = Profile.new(email)
|
188
|
+
user.articles = [Article.new(title, body)]
|
189
|
+
UserResource.new(user).serialize
|
190
|
+
# => '{"user":{"id":id, "created_at": created_at, "updated_at": updated_at, "profile": {"email": email}, articles: [{"title": title, "body": body}]}'
|
191
|
+
|
192
|
+
# or #attribute
|
193
|
+
class UserResource
|
194
|
+
include Alba::Resource
|
195
|
+
root_key :user
|
196
|
+
attributes :id, :created_at, :updated_at
|
197
|
+
|
198
|
+
attribute :profile do
|
199
|
+
{
|
200
|
+
email: object.profile.email # Can access to received resource by #object method
|
201
|
+
}
|
202
|
+
end
|
203
|
+
|
204
|
+
attribute :articles do
|
205
|
+
object.articles.map do |article|
|
206
|
+
{
|
207
|
+
title: article.title,
|
208
|
+
body: article.body,
|
209
|
+
}
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
user = User.new(id)
|
214
|
+
user.profile = Profile.new(email)
|
215
|
+
UserResource.new(user).serialize
|
216
|
+
# => '{"user":{"id":id, "created_at": created_at, "updated_at": updated_at, "profile": {"email": email}, articles: [{"title": title, "body": body}]}'
|
217
|
+
```
|
218
|
+
|
219
|
+
## 3. Unsupported features
|
220
|
+
|
221
|
+
- Jbuilder#ignore_nil!
|
222
|
+
- Jbuilder#cache!
|
223
|
+
- Jbuilder.key_format! and Jbuilder.deep_format_keys!
|
data/gemfiles/all.gemfile
CHANGED
@@ -11,7 +11,7 @@ gem 'rubocop-rake', '>= 0.5.1', require: false # For lint
|
|
11
11
|
gem 'rubocop-sensible', '~> 0.3.0', require: false # For lint
|
12
12
|
gem 'simplecov', '~> 0.21.0', require: false # For test coverage
|
13
13
|
gem 'simplecov-cobertura', require: false # For test coverage
|
14
|
-
gem 'yard', require: false
|
14
|
+
gem 'yard', require: false # For documentation
|
15
15
|
|
16
16
|
platforms :ruby do
|
17
17
|
gem 'oj', '~> 3.11', require: false # For backend
|
@@ -9,7 +9,7 @@ gem 'rubocop-rake', '>= 0.5.1', require: false # For lint
|
|
9
9
|
gem 'rubocop-sensible', '~> 0.3.0', require: false # For lint
|
10
10
|
gem 'simplecov', '~> 0.21.0', require: false # For test coverage
|
11
11
|
gem 'simplecov-cobertura', require: false # For test coverage
|
12
|
-
gem 'yard', require: false
|
12
|
+
gem 'yard', require: false # For documentation
|
13
13
|
|
14
14
|
platforms :ruby do
|
15
15
|
gem 'oj', '~> 3.11', require: false # For backend
|
data/gemfiles/without_oj.gemfile
CHANGED
@@ -10,7 +10,7 @@ gem 'rubocop-rake', '>= 0.5.1', require: false # For lint
|
|
10
10
|
gem 'rubocop-sensible', '~> 0.3.0', require: false # For lint
|
11
11
|
gem 'simplecov', '~> 0.21.0', require: false # For test coverage
|
12
12
|
gem 'simplecov-cobertura', require: false # For test coverage
|
13
|
-
gem 'yard', require: false
|
13
|
+
gem 'yard', require: false # For documentation
|
14
14
|
|
15
15
|
platforms :ruby do
|
16
16
|
gem 'ruby-prof', require: false # For performance profiling
|
data/lib/alba/association.rb
CHANGED
@@ -2,11 +2,12 @@ module Alba
|
|
2
2
|
# Base class for `One` and `Many`
|
3
3
|
# Child class should implement `to_hash` method
|
4
4
|
class Association
|
5
|
-
attr_reader :object
|
5
|
+
attr_reader :object, :name
|
6
6
|
|
7
|
-
# @param name [Symbol] name of the method to fetch association
|
8
|
-
# @param condition [Proc] a proc filtering data
|
9
|
-
# @param resource [Class<Alba::Resource
|
7
|
+
# @param name [Symbol, String] name of the method to fetch association
|
8
|
+
# @param condition [Proc, nil] a proc filtering data
|
9
|
+
# @param resource [Class<Alba::Resource>, nil] a resource class for the association
|
10
|
+
# @param nesting [String] a namespace where source class is inferred with
|
10
11
|
# @param block [Block] used to define resource when resource arg is absent
|
11
12
|
def initialize(name:, condition: nil, resource: nil, nesting: nil, &block)
|
12
13
|
@name = name
|
@@ -15,14 +16,7 @@ module Alba
|
|
15
16
|
@resource = resource
|
16
17
|
return if @resource
|
17
18
|
|
18
|
-
|
19
|
-
@resource = resource_class
|
20
|
-
elsif Alba.inferring
|
21
|
-
const_parent = nesting.nil? ? Object : Object.const_get(nesting)
|
22
|
-
@resource = const_parent.const_get("#{ActiveSupport::Inflector.classify(@name)}Resource")
|
23
|
-
else
|
24
|
-
raise ArgumentError, 'When Alba.inferring is false, either resource or block is required'
|
25
|
-
end
|
19
|
+
assign_resource(nesting)
|
26
20
|
end
|
27
21
|
|
28
22
|
private
|
@@ -36,11 +30,14 @@ module Alba
|
|
36
30
|
end
|
37
31
|
end
|
38
32
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
33
|
+
def assign_resource(nesting)
|
34
|
+
@resource = if @block
|
35
|
+
Alba.resource_class(&@block)
|
36
|
+
elsif Alba.inferring
|
37
|
+
Alba.infer_resource_class(@name, nesting: nesting)
|
38
|
+
else
|
39
|
+
raise ArgumentError, 'When Alba.inferring is false, either resource or block is required'
|
40
|
+
end
|
44
41
|
end
|
45
42
|
end
|
46
43
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Alba
|
2
|
+
# This module represents the inflector, which is used by default
|
3
|
+
module DefaultInflector
|
4
|
+
begin
|
5
|
+
require 'active_support/inflector'
|
6
|
+
rescue LoadError
|
7
|
+
raise ::Alba::Error, 'To use transform_keys, please install `ActiveSupport` gem.'
|
8
|
+
end
|
9
|
+
|
10
|
+
module_function
|
11
|
+
|
12
|
+
# Camelizes a key
|
13
|
+
#
|
14
|
+
# @param key [String] key to be camelized
|
15
|
+
# @return [String] camelized key
|
16
|
+
def camelize(key)
|
17
|
+
ActiveSupport::Inflector.camelize(key)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Camelizes a key, 1st letter lowercase
|
21
|
+
#
|
22
|
+
# @param key [String] key to be camelized
|
23
|
+
# @return [String] camelized key
|
24
|
+
def camelize_lower(key)
|
25
|
+
ActiveSupport::Inflector.camelize(key, false)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Dasherizes a key
|
29
|
+
#
|
30
|
+
# @param key [String] key to be dasherized
|
31
|
+
# @return [String] dasherized key
|
32
|
+
def dasherize(key)
|
33
|
+
ActiveSupport::Inflector.dasherize(key)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Alba
|
2
|
+
# Module for printing deprecation warning
|
3
|
+
module Deprecation
|
4
|
+
# Similar to {Kernel.warn} but prints caller as well
|
5
|
+
#
|
6
|
+
# @param message [String] main message to print
|
7
|
+
# @return void
|
8
|
+
def warn(message)
|
9
|
+
Kernel.warn(message)
|
10
|
+
Kernel.warn(caller_locations(2..2).first) # For performance reason we use (2..2).first
|
11
|
+
end
|
12
|
+
module_function :warn
|
13
|
+
end
|
14
|
+
end
|