active_loaders 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGES.md +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +464 -0
- data/Rakefile +2 -0
- data/active_loaders.gemspec +30 -0
- data/lib/active_loaders.rb +6 -0
- data/lib/active_loaders/datasource_adapter.rb +216 -0
- data/lib/active_loaders/test.rb +100 -0
- data/lib/active_loaders/version.rb +3 -0
- data/spec/sequel_serializer_spec.rb +65 -0
- data/spec/sequel_skip_select_spec.rb +77 -0
- data/spec/serializer_spec.rb +62 -0
- data/spec/skip_select_spec.rb +74 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/support/db.rb +53 -0
- data/spec/test_methods_spec.rb +57 -0
- metadata +211 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1c20db7715ae3e3c92b94cae3b9f0f581b8250c0
|
4
|
+
data.tar.gz: 8d30e6a5d26a8da199891149ed1e0065c23b019b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3ac7046e5f186c6d2261b6d9622e96270471ba7375f01f33cb056fb0616c755d53467b7359859abae62313977d5f5225337a9634f6f004db7b23288c0ff2135b
|
7
|
+
data.tar.gz: 4f9322f159b82a4ba35c4229c08d1465e71e53b46e64248ee97850292897cd6244a51394286914057498084bacef10f8673fa9086a024b71a4dea9650213298a
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
active_loaders
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.2.0
|
data/CHANGES.md
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
### 0.0.1
|
2
|
+
|
3
|
+
- the following are changes from what was previously in the datasource gem
|
4
|
+
- change Serializer datasource_select method to loaders { select(...) }
|
5
|
+
- change Serializer datasource_includes method to loaders { includes(...) }
|
6
|
+
- render method: rename datasource_params to loader_params
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Jan Berdajs
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,464 @@
|
|
1
|
+
# ActiveLoaders
|
2
|
+
|
3
|
+
- Automatically preload associations for your serializers
|
4
|
+
- Specify custom SQL snippets for virtual attributes (Query attributes)
|
5
|
+
- Write custom preloading logic in a reusable way
|
6
|
+
|
7
|
+
*Note: the API of this gem is still unstable and may change between versions. This project uses semantic versioning, however until version 1.0.0, minor version (MAJOR.MINOR.PATCH) changes may include API changes, but patch version will not)*
|
8
|
+
|
9
|
+
<a href="http://www.youtube.com/watch?feature=player_embedded&v=ajSNCbZYqKk
|
10
|
+
" target="_blank"><img src="http://img.youtube.com/vi/ajSNCbZYqKk/0.jpg"
|
11
|
+
alt="Datasource talk" width="240" height="180" border="10" /><br>A 30-min talk about Datasource</a>
|
12
|
+
|
13
|
+
#### Install
|
14
|
+
|
15
|
+
Ruby version requirement:
|
16
|
+
|
17
|
+
- MRI 2.0 or higher
|
18
|
+
- JRuby 9000
|
19
|
+
|
20
|
+
Supported ORM:
|
21
|
+
|
22
|
+
- ActiveRecord
|
23
|
+
- Sequel
|
24
|
+
|
25
|
+
Add to Gemfile (recommended to use github version until API is stable)
|
26
|
+
|
27
|
+
```
|
28
|
+
gem 'active_loaders', github: 'kundi/active_loaders'
|
29
|
+
```
|
30
|
+
|
31
|
+
```
|
32
|
+
bundle install
|
33
|
+
rails g datasource:install
|
34
|
+
```
|
35
|
+
|
36
|
+
#### Upgrade
|
37
|
+
|
38
|
+
```
|
39
|
+
rails g datasource:install
|
40
|
+
```
|
41
|
+
|
42
|
+
### Introduction
|
43
|
+
|
44
|
+
The most important role of ActiveLoaders is to help prevent and fix the
|
45
|
+
[N+1 queries problem](http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations)
|
46
|
+
when using Active Model Serializers.
|
47
|
+
|
48
|
+
This gem depends on the datasource gem that handles actual data loading. What this gem
|
49
|
+
adds on top of it is integration with Active Model Serializers. It will automatically
|
50
|
+
read your serializers to make datasource preload the necessary associations. Additionally
|
51
|
+
it provides a simple DSL to configure additional dependencies and test helpers to ensure
|
52
|
+
your queries are optimized.
|
53
|
+
|
54
|
+
ActiveLoaders will automatically recognize associations in your **serializer** when you use
|
55
|
+
the `has_many` or `belongs_to` keywords:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
class PostSerializer < ActiveModel::Serializer
|
59
|
+
belongs_to :blog
|
60
|
+
has_many :comments
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
In this case, it will then look in your BlogSerializer and CommentSerializer to properly
|
65
|
+
load them as well (so it is recursive).
|
66
|
+
|
67
|
+
When you are using loaded values (explained below), ActiveLoaders will automatically
|
68
|
+
use them if you specify the name in `attributes`. For example if you have a
|
69
|
+
`loaded :comment_count` it will automatically be used if you have
|
70
|
+
`attributes :comment_count` in your serializer.
|
71
|
+
|
72
|
+
In case ActiveLoaders doesn't automatically detect something, you can always manually
|
73
|
+
specify it in your serializer using a simple DSL.
|
74
|
+
|
75
|
+
A test helper is also provided which you can ensure that your serializers don't produce
|
76
|
+
N+1 queries.
|
77
|
+
|
78
|
+
### Associations
|
79
|
+
|
80
|
+
The most noticable magic effect of using ActiveLoaders is that associations will
|
81
|
+
automatically be preloaded using a single query.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
class PostSerializer < ActiveModel::Serializer
|
85
|
+
attributes :id, :title
|
86
|
+
end
|
87
|
+
|
88
|
+
class UserSerializer < ActiveModel::Serializer
|
89
|
+
attributes :id
|
90
|
+
has_many :posts
|
91
|
+
end
|
92
|
+
```
|
93
|
+
```sql
|
94
|
+
SELECT users.* FROM users
|
95
|
+
SELECT posts.* FROM posts WHERE id IN (?)
|
96
|
+
```
|
97
|
+
|
98
|
+
This means you **do not** need to call `includes` yourself. It will be done
|
99
|
+
automatically.
|
100
|
+
|
101
|
+
#### Manually include
|
102
|
+
|
103
|
+
In case you are not using `has_many` or `belongs_to` in your serializer but you are
|
104
|
+
still using the association (usually when you do not embed the association), then you
|
105
|
+
need to manually specify this in your serializer. There are two options depending on
|
106
|
+
what data you need.
|
107
|
+
|
108
|
+
**includes**: use this when you just need a simple `includes`, which behaves the same
|
109
|
+
as in ActiveRecord.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
class UserSerializer < ActiveModel::Serializer
|
113
|
+
attributes :id, :post_titles
|
114
|
+
loaders do
|
115
|
+
includes :posts
|
116
|
+
# includes posts: { :comments }
|
117
|
+
end
|
118
|
+
|
119
|
+
def post_titles
|
120
|
+
object.posts.map(&:title)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
**select**: use this to use the serializer loading logic - the same recursive logic that
|
126
|
+
happens when you use `has_many` or `belongs_to`. This will also load associations and
|
127
|
+
loaded values (unless otherwise specified).
|
128
|
+
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
class UserSerializer < ActiveModel::Serializer
|
132
|
+
attributes :id, :comment_loaded_values
|
133
|
+
loaders do
|
134
|
+
select :posts
|
135
|
+
# select posts: [:id, comments: [:id, :some_loaded_value]]
|
136
|
+
end
|
137
|
+
|
138
|
+
def comment_loaded_values
|
139
|
+
object.posts.flat_map(&:comments).map(&:some_loaded_value)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class PostSerializer < ActiveModel::Serializer
|
144
|
+
attributes :id
|
145
|
+
has_many :comments
|
146
|
+
end
|
147
|
+
|
148
|
+
class CommentSerializer < ActiveModel::Serializer
|
149
|
+
attributes :id, :some_loaded_value
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
### Query attribute
|
154
|
+
|
155
|
+
You can specify a SQL fragment for `SELECT` and use that as an attribute on your
|
156
|
+
model. This is done through the datasource gem DSL. As a simple example you can
|
157
|
+
concatenate 2 strings together in SQL:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
class User < ActiveRecord::Base
|
161
|
+
datasource_module do
|
162
|
+
query :full_name do
|
163
|
+
"users.first_name || ' ' || users.last_name"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class UserSerializer < ActiveModel::Serializer
|
169
|
+
attributes :id, :full_name
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
```sql
|
174
|
+
SELECT users.*, (users.first_name || ' ' || users.last_name) AS full_name FROM users
|
175
|
+
```
|
176
|
+
|
177
|
+
Note: If you need data from another table, use a loaded value.
|
178
|
+
|
179
|
+
### Refactor with standalone Datasource class
|
180
|
+
|
181
|
+
If you are going to have more complex preloading logic (like using Loaded below),
|
182
|
+
then it might be better to put Datasource code into its own class. This is pretty
|
183
|
+
easy, just create a directory `app/datasources` (or whatever you like), and create
|
184
|
+
a file depending on your model name, for example for a `Post` model, create
|
185
|
+
`post_datasource.rb`. The name is important for auto-magic reasons. Example file:
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
class PostDatasource < Datasource::From(Post)
|
189
|
+
query(:full_name) { "users.first_name || ' ' || users.last_name" }
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
This is completely equivalent to using `datasource_module` in your model:
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
class Post < ActiveRecord::Base
|
197
|
+
datasource_module do
|
198
|
+
query(:full_name) { "users.first_name || ' ' || users.last_name" }
|
199
|
+
end
|
200
|
+
end
|
201
|
+
```
|
202
|
+
|
203
|
+
### Loaded
|
204
|
+
|
205
|
+
You might want to have some more complex preloading logic. In that case you can
|
206
|
+
use a method to load values for all the records at once (e.g. with a custom query
|
207
|
+
or even from a cache). The loading methods are only executed if you use the values,
|
208
|
+
otherwise they will be skipped.
|
209
|
+
|
210
|
+
First just declare that you want to have a loaded attribute (the parameters will be explained shortly):
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
class UserDatasource < Datasource::From(User)
|
214
|
+
loaded :post_count, from: :array, default: 0
|
215
|
+
end
|
216
|
+
```
|
217
|
+
|
218
|
+
By default, datasource will look for a method named `load_<name>` for loading
|
219
|
+
the values, in this case `load_newest_comment`. It needs to be defined in the
|
220
|
+
collection block, which has methods to access information about the collection (posts)
|
221
|
+
that are being loaded. These methods are `scope`, `models`, `model_ids`,
|
222
|
+
`datasource`, `datasource_class` and `params`.
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
class UserDatasource < Datasource::From(User)
|
226
|
+
loaded :post_count, from: :array, default: 0
|
227
|
+
|
228
|
+
collection do
|
229
|
+
def load_post_count
|
230
|
+
Post.where(user_id: model_ids)
|
231
|
+
.group(:user_id)
|
232
|
+
.pluck("user_id, COUNT(id)")
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
```
|
237
|
+
|
238
|
+
In this case `load_post_count` returns an array of pairs.
|
239
|
+
For example: `[[1, 10], [2, 5]]`. Datasource can understand this because of
|
240
|
+
`from: :array`. This would result in the following:
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
post_id_1.post_count # => 10
|
244
|
+
post_id_2.post_count # => 5
|
245
|
+
# other posts will have the default value or nil if no default value was given
|
246
|
+
other_post.post_count # => 0
|
247
|
+
```
|
248
|
+
|
249
|
+
Besides `default` and `from: :array`, you can also specify `group_by`, `one`
|
250
|
+
and `source`. Source is just the name of the load method.
|
251
|
+
|
252
|
+
The other two are explained in the following example.
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
class PostDatasource < Datasource::From(Post)
|
256
|
+
loaded :newest_comment, group_by: :post_id, one: true, source: :load_newest_comment
|
257
|
+
|
258
|
+
collection do
|
259
|
+
def load_newest_comment
|
260
|
+
Comment.for_serializer.where(post_id: model_ids)
|
261
|
+
.group("post_id")
|
262
|
+
.having("id = MAX(id)")
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
```
|
267
|
+
|
268
|
+
In this case the load method returns an ActiveRecord relation, which for our purposes
|
269
|
+
acts the same as an Array (so we could also return an Array if we wanted).
|
270
|
+
Using `group_by: :post_id` in the `loaded` call tells datasource to group the
|
271
|
+
results in this array by that attribute (or key if it's an array of hashes instead
|
272
|
+
of model objects). `one: true` means that we only want a single value instead of
|
273
|
+
an array of values (we might want multiple, e.g. `newest_10_comments`).
|
274
|
+
So in this case, if we had a Post with id 1, `post.newest_comment` would be a
|
275
|
+
Comment from the array that has `post_id` equal to 1.
|
276
|
+
|
277
|
+
In this case, in the load method, we also used `for_serializer`, which will load
|
278
|
+
the `Comment`s according to the `CommentSerializer`.
|
279
|
+
|
280
|
+
Note that it's perfectly fine (even recommended) to already have a method with the same
|
281
|
+
name in your model.
|
282
|
+
If you use that method outside of serializers/datasource, it will work just as
|
283
|
+
it should. But when using datasource, it will be overwritten by the datasource
|
284
|
+
version. Counts is a good example:
|
285
|
+
|
286
|
+
```ruby
|
287
|
+
class User < ActiveRecord::Base
|
288
|
+
has_many :posts
|
289
|
+
|
290
|
+
def post_count
|
291
|
+
posts.count
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
class UserDatasource < Datasource::From(User)
|
296
|
+
loaded :post_count, from: :array, default: 0
|
297
|
+
|
298
|
+
collection do
|
299
|
+
def load_post_count
|
300
|
+
Post.where(user_id: model_ids)
|
301
|
+
.group(:user_id)
|
302
|
+
.pluck("user_id, COUNT(id)")
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
class UserSerializer < ActiveModel::Serializer
|
308
|
+
attributes :id, :post_count # <- post_count will be read from load_post_count
|
309
|
+
end
|
310
|
+
|
311
|
+
User.first.post_count # <- your model method will be called
|
312
|
+
```
|
313
|
+
|
314
|
+
### Params
|
315
|
+
|
316
|
+
You can also specify params that can be read from collection methods. The params
|
317
|
+
can be specified when you call `render`:
|
318
|
+
|
319
|
+
```ruby
|
320
|
+
# controller
|
321
|
+
render json: posts,
|
322
|
+
loader_params: { include_newest_comments: true }
|
323
|
+
|
324
|
+
# datasource
|
325
|
+
loaded :newest_comments, default: []
|
326
|
+
|
327
|
+
collection do
|
328
|
+
def load_newest_comments
|
329
|
+
if params[:include_newest_comments]
|
330
|
+
# ...
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
```
|
335
|
+
|
336
|
+
### Debugging and logging
|
337
|
+
|
338
|
+
Datasource outputs some useful logs that you can use debugging. By default the log level is
|
339
|
+
set to warnings only, but you can change it. You can add the following line at the end of your
|
340
|
+
`config/initializers/datasource.rb`:
|
341
|
+
|
342
|
+
```ruby
|
343
|
+
Datasource.logger.level = Logger::INFO unless Rails.env.production?
|
344
|
+
```
|
345
|
+
|
346
|
+
You can also set it to `DEBUG` for more output. The logger outputs to `stdout` by default. It
|
347
|
+
is not recommended to have this enabled in production (simply for performance reasons).
|
348
|
+
|
349
|
+
### Using manually
|
350
|
+
|
351
|
+
When using a serializer, ActiveLoaders should work automatically. If for some reason
|
352
|
+
you want to manually trigger loaders on a scope, you can call `for_serializer`.
|
353
|
+
|
354
|
+
```ruby
|
355
|
+
Post.for_serializer.find(params[:id])
|
356
|
+
Post.for_serializer(PostSerializer).find(params[:id])
|
357
|
+
Post.for_serializer.where("created_at > ?", 1.day.ago).to_a
|
358
|
+
```
|
359
|
+
|
360
|
+
You can also use it on an existing record, but you must use the returned value (the record
|
361
|
+
may be reloaded e.g. if you are using query attributes).
|
362
|
+
|
363
|
+
```ruby
|
364
|
+
user = current_user.for_serializer
|
365
|
+
```
|
366
|
+
|
367
|
+
For even more advanced usage, see Datasource gem documentation.
|
368
|
+
|
369
|
+
### Testing your serializer queries
|
370
|
+
|
371
|
+
ActiveLoaders provides test helpers to make sure your queries stay optimized. By default
|
372
|
+
it expects there to be no N+1 queries, so after the initial loading of the records and
|
373
|
+
associations, there should be no queries from code in the serializers. The helpers raise
|
374
|
+
and error otherwise, so you can use them with any testing framework (rspec, minitest).
|
375
|
+
You need to put some records into the database before calling the helper, since it is
|
376
|
+
required to be able to test the serializer.
|
377
|
+
|
378
|
+
```ruby
|
379
|
+
test_serializer_queries(serializer_class, model_class, options = {})
|
380
|
+
```
|
381
|
+
|
382
|
+
Here is a simple example in rspec with factory_girl:
|
383
|
+
|
384
|
+
```ruby
|
385
|
+
context "serializer queries" do
|
386
|
+
let(:blog) { create :blog }
|
387
|
+
before do
|
388
|
+
2.times {
|
389
|
+
create :post, blog_id: blog.id
|
390
|
+
}
|
391
|
+
end
|
392
|
+
|
393
|
+
it "should not contain N+1 queries" do
|
394
|
+
expect { test_serializer_queries(BlogSerializer, Blog) }.to_not raise_error
|
395
|
+
end
|
396
|
+
|
397
|
+
# example if you have N+1 queries and you can't avoid them
|
398
|
+
it "should contain exactly two N+1 queries (two queries for every Blog)" do
|
399
|
+
expect { test_serializer_queries(BlogSerializer, Blog, allow_queries_per_record: 2) }.to_not raise_error
|
400
|
+
end
|
401
|
+
end
|
402
|
+
```
|
403
|
+
|
404
|
+
#### Columns check
|
405
|
+
|
406
|
+
Recently (not yet released as of Rails 4.2), an `accessed_fields` instance method
|
407
|
+
was added to ActiveRecord models. ActiveLoaders can use this information in your
|
408
|
+
tests to determine which attributes you are not using in your serializer. This check
|
409
|
+
is skipped if your Rails version doesn't support `accessed_fields`.
|
410
|
+
|
411
|
+
Let's say your are not using User#payment_data in your serializer. You have this test:
|
412
|
+
|
413
|
+
```ruby
|
414
|
+
it "should not contain N+1 queries" do
|
415
|
+
expect { test_serializer_queries(UserSerializer, User) }.to_not raise_error
|
416
|
+
end
|
417
|
+
```
|
418
|
+
|
419
|
+
Then this test will fail with instructions on how to fix it:
|
420
|
+
|
421
|
+
```ruby
|
422
|
+
ActiveLoaders::Test::Error:
|
423
|
+
unnecessary select for User columns: payment_data
|
424
|
+
|
425
|
+
Add to UserSerializer loaders block:
|
426
|
+
skip_select :payment_data
|
427
|
+
|
428
|
+
Or ignore this error with:
|
429
|
+
test_serializer_queries(UserSerializer, User, ignore_columns: [:payment_data])
|
430
|
+
|
431
|
+
Or skip this columns check entirely:
|
432
|
+
test_serializer_queries(UserSerializer, User, skip_columns_check: true)
|
433
|
+
```
|
434
|
+
|
435
|
+
The instructions should be self-explanatory. Choosing the first option:
|
436
|
+
|
437
|
+
```ruby
|
438
|
+
class UserSerializer < ActiveModel::Serializer
|
439
|
+
attributes :id, :title
|
440
|
+
|
441
|
+
loaders do
|
442
|
+
skip_select :payment_data
|
443
|
+
end
|
444
|
+
end
|
445
|
+
```
|
446
|
+
|
447
|
+
Would then produce an optimized query:
|
448
|
+
```sql
|
449
|
+
SELECT users.id, users.title FROM users
|
450
|
+
```
|
451
|
+
|
452
|
+
## Getting Help
|
453
|
+
|
454
|
+
If you find a bug, please report an [Issue](https://github.com/kundi/active_loaders/issues/new).
|
455
|
+
|
456
|
+
If you have a question, you can also open an Issue.
|
457
|
+
|
458
|
+
## Contributing
|
459
|
+
|
460
|
+
1. Fork it ( https://github.com/kundi/active_loaders/fork )
|
461
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
462
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
463
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
464
|
+
5. Create a new Pull Request
|