api-blocks 0.4.11 → 0.5.0

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: 213ea14d1ace477c4e700647a5574a5a9024c62185a9a2e5b656a2ed7b2f3eb0
4
- data.tar.gz: 74cf4dd8fb59ff2441e0effa5217b200e6cb4bf4e2539c3882709e93bb46a7d4
3
+ metadata.gz: 710664013c6c921b9bdfe46c1598143edd489eddcdfc1519f13fb2625462640a
4
+ data.tar.gz: 245c76d099c43ffa562ed68bbc387deb49d7fd96814ed294eee1eccbf1b3adad
5
5
  SHA512:
6
- metadata.gz: 648bc25b3c823f66c65edf674e283eb24803d9f9af7afc00e6a8b6683c66099b00510c775d4a66658a4fea2b01f8cd47a380b61e1870889815dd76f0f6523f99
7
- data.tar.gz: 87e3687c96f08d74ff264761a89f2642277e58d73da5acf910e035347aa89b62358a0f687ddd4aab3a177a8dd39b0a99bb4cc7ee1b2019895a96d14c304fbe44
6
+ metadata.gz: 471441ab9dab08080f516f2a8427938f739154b91f24dd0378f48634f9b4bf444e9103af4c6d49905002d847d9b03a2dab1f0f87edafa7661ad2163f00e12272
7
+ data.tar.gz: 3273523f2ecc5997e7cc0ea04eb8bfc7e88b75723293cd1268b7cf21fd6c07ff45daf969402c0245ddde8eb33753fc25546ca851163f946bd233fddbdbb63c1d
data/lib/api_blocks.rb CHANGED
@@ -3,6 +3,8 @@
3
3
  require 'rubygems'
4
4
  require 'bundler/setup'
5
5
 
6
+ require 'dry/configurable'
7
+
6
8
  require 'api_blocks/version'
7
9
  require 'active_support/concern'
8
10
  require 'active_support/dependencies/autoload'
@@ -15,6 +17,12 @@ module ApiBlocks
15
17
  autoload :Responder
16
18
  autoload :Interactor
17
19
  autoload :Doorkeeper
20
+
21
+ extend Dry::Configurable
22
+
23
+ setting :blueprinter do
24
+ setting :use_batch_loader, false
25
+ end
18
26
  end
19
27
 
20
28
  require 'api_blocks/railtie' if defined?(Rails)
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Monkey-patch Blueprinter::AssociationExtractor to use `batch-loader` gem in
4
+ # order to avoid n+1 queries when serializing associations.
5
+ #
6
+ # This does not support associations defined using a `proc` as
7
+ # `options[:blueprint]`
8
+ #
9
+ class Blueprinter::AssociationExtractor < Blueprinter::Extractor
10
+ def extract(association_name, object, local_options, options = {})
11
+ if options[:blueprint].is_a?(Proc)
12
+ raise "Cannot load blueprints with a `proc` blueprint option with batch-loader"
13
+ end
14
+
15
+ association = object.association(association_name)
16
+
17
+ join_key = association.reflection.join_keys
18
+ association_id = object.send(join_key.foreign_key)
19
+ association_klass = association.reflection.class_name
20
+
21
+ default_value = case association
22
+ when ActiveRecord::Associations::HasManyAssociation
23
+ []
24
+ end
25
+
26
+ view = options[:view] || :default
27
+
28
+ BatchLoader.for(association_id).batch(
29
+ default_value: default_value,
30
+ key: [association_name, association_klass, view, options[:blueprint]],
31
+ ) do |ids, loader, _args|
32
+ model = association_klass.safe_constantize
33
+
34
+ case association
35
+ when ActiveRecord::Associations::HasManyAssociation
36
+ model.where(join_key.key => ids).each do |record|
37
+ loader.call(record.send(join_key.key)) do |memo|
38
+ memo << render_blueprint(record, local_options, options)
39
+ end
40
+ end
41
+ when ActiveRecord::Associations::HasOneAssociation
42
+ model.where(join_key.key => ids).each do |record|
43
+ loader.call(
44
+ record.send(join_key.key),
45
+ render_blueprint(record, local_options, options)
46
+ )
47
+ end
48
+ when ActiveRecord::Associations::BelongsToAssociation
49
+ model.where(join_key.key => ids).each do |record|
50
+ loader.call(
51
+ record.id,
52
+ render_blueprint(record, local_options, options)
53
+ )
54
+ end
55
+ else
56
+ raise "unsupported association kind #{association.class.name}"
57
+ end
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def render_blueprint(value, local_options, options = {})
64
+ return default_value(options) if value.nil?
65
+
66
+ view = options[:view] || :default
67
+ blueprint = association_blueprint(options[:blueprint], value)
68
+ blueprint.prepare(value, view_name: view, local_options: local_options)
69
+ end
70
+ end
@@ -11,4 +11,12 @@ class ApiBlocks::Railtie < Rails::Railtie
11
11
  require_relative 'doorkeeper/passwords/migration_generator'
12
12
  require_relative 'doorkeeper/invitations/migration_generator'
13
13
  end
14
+
15
+ initializer "blueprinter.batch_loader_integration" do |app|
16
+ app.config.after_initialize do
17
+ next unless ApiBlocks.config.blueprinter.use_batch_loader
18
+
19
+ require_relative "blueprinter/association_extractor"
20
+ end
21
+ end
14
22
  end
@@ -67,7 +67,7 @@ class ApiBlocks::Responder < ActionController::Responder
67
67
  super
68
68
  end
69
69
 
70
- def json_resource_errors
70
+ def json_sesource_errors
71
71
  [{ errors: resource.errors }, :unprocessable_entity]
72
72
  end
73
73
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  module ApiBlocks
4
4
  # Current version of ApiBlocks
5
- VERSION = "0.4.11"
5
+ VERSION = "0.5.0"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api-blocks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.11
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul d'Hubert
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: 3.0.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: dry-configurable
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.8'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.8'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: bundler
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -256,6 +270,7 @@ extra_rdoc_files: []
256
270
  files:
257
271
  - lib/api-blocks.rb
258
272
  - lib/api_blocks.rb
273
+ - lib/api_blocks/blueprinter/association_extractor.rb
259
274
  - lib/api_blocks/controller.rb
260
275
  - lib/api_blocks/doorkeeper.rb
261
276
  - lib/api_blocks/doorkeeper/invitations.rb