nexaas-async-collector 3.0.1 → 3.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee2109580d4539bc01aa2015e35fdb66a03a5e47
4
- data.tar.gz: b36924123c2122b0fec86735195899cb0fa70b2c
3
+ metadata.gz: 22260bccd9579781a6b6ca2dadc82198a30cbb01
4
+ data.tar.gz: ddfe6e2396e4229904ff1f4084a498913813cd7c
5
5
  SHA512:
6
- metadata.gz: 965dd0712b7f5d4e6cc82be1a1ccbf256a74a95253ab155759f8934e84d92fbcefea0fc673d23e98847330867b3ecf52f4a55a6ca3204c61beb449b783c76169
7
- data.tar.gz: abbae053baa51b8313e474544a56bcfcdd448f98539244fb330ef7fb11de8121e9fa3d98ddd0ce809c6f5531dbacfeb3ae42d78de39a1d8a56e9c0e28c3343c3
6
+ metadata.gz: 9029f15e453e1c4ef0a53cbe2cfcd9a320376acb8761b7b4bedf9470abb529212b4403ba751fe5417bd7b90258a8bfbf96cdb06c6acdbb4fd11c19b03a205b4e
7
+ data.tar.gz: 1b03833b73d63e95f5988681cad00ec5035a3d5dac53ab7d2f8d60579502bae2667983d48856dfaf7211d15ef8a3cd57c37f6769d49831dcf5f163069b6f87c1
data/README.md CHANGED
@@ -78,6 +78,28 @@ end
78
78
  }) %>
79
79
  ```
80
80
 
81
+ ### Download file
82
+
83
+ Instead of rendering text or HTML, you can use `nexaas-async-collect` to generate files, so the user can download it.
84
+
85
+ If you want to export something to `xls` file, for example:
86
+
87
+ ```ruby
88
+ <%= nexaas_async_collect({
89
+ scope_id: scope.id, # (required)
90
+ class_name: ModelService, # (required)
91
+ class_method: :model_method, # (required)
92
+ args: [arg1, arg2], # (optional)
93
+ file: {
94
+ content_type: 'application/vnd.ms-excel', # (required) content type of the file
95
+ name: 'reports', # (required) name of the file
96
+ extension: 'xls' # (require) extension of the file
97
+ }
98
+ }) %>
99
+ ```
100
+
101
+ This will generate the spinner and it will redirect the user to download the file when it is ready.
102
+
81
103
  ## Contributing
82
104
  Bug reports and pull requests are welcome on GitHub at [https://github.com/myfreecomm/nexaas-async-collector](https://github.com/myfreecomm/nexaas-async-collector). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
83
105
 
@@ -4,20 +4,29 @@ module Nexaas
4
4
  module Async
5
5
  module Collector
6
6
  class AsyncResourceController < ApplicationController
7
+
7
8
  def show
8
9
  @result = Result.new(collector_scope.id, params[:id])
9
10
  @unique_id = params[:unique_id]
10
- respond_to { |f| f.js }
11
+ respond_to do |format|
12
+ render_for_request(format)
13
+ end
11
14
  end
12
15
 
13
16
  private
14
17
 
15
- def nexaas_async_collector_scope
16
- Nexaas::Async::Collector.scope
18
+ def render_for_request(format)
19
+ format.js { render :show }
20
+ format.all do
21
+ send_data(@result.content, {
22
+ filename: "#{@result.filename}.#{@result.extension}", type: @result.content_type,
23
+ disposition: 'attachment'
24
+ })
25
+ end
17
26
  end
18
27
 
19
28
  def collector_scope
20
- send(nexaas_async_collector_scope)
29
+ send(Nexaas::Async::Collector.scope)
21
30
  end
22
31
  end
23
32
  end
@@ -2,21 +2,32 @@ module Nexaas
2
2
  module Async
3
3
  module Collector
4
4
  module ApplicationHelper
5
+
5
6
  #
6
7
  # Helper to enqueue AsyncResourceJob and include the JavaScript code to request the result
7
8
  # - scope_id: an ID that is unique (maybe user.id, account.id, organization.id, etc)
8
9
  # - klass_name: The name of the class responsible for generate the content to be stored in the memory
9
10
  # - klass_method: The name of the class method to be called
10
11
  # - args: The arguments to be passed in the call of the class method
12
+ # - instrumentation_context: Custom context for instrumentatio with ActiveSupport::Notifications
13
+ # - file: Argument to pass file informations. This will be used to generated file for the user
14
+ # - conten_type: Content type of the file
15
+ # - name: Basename of the file to be generated
11
16
  #
12
17
  # Example:
13
- # <%= nexaas_async_collect(current_user.id, ReportGenerator, :generate, []) %>
18
+ # <%= nexaas_async_collect({
19
+ # scope_id: current_user.id, class_name: ReportGenerator,
20
+ # class_method: :generate, args: [],
21
+ # file: { content_type: 'application/json', name: 'data' }
22
+ # }) %>
14
23
  #
15
24
  def nexaas_async_collect(opts={})
16
- validate_options(opts)
17
- opts.merge!({ collect_id: collect_id })
18
- AsyncResourceJob.perform_async(opts)
19
- render(partial: 'nexaas/async/collector/async_resource/show', locals: { unique_id: SecureRandom.hex })
25
+ async_resource = Nexaas::Async::Collector::AsyncResource.new(opts)
26
+ async_resource.save!
27
+ render(partial: 'nexaas/async/collector/async_resource/show', locals: {
28
+ unique_id: SecureRandom.hex,
29
+ collect_id: async_resource.collect_id
30
+ })
20
31
  end
21
32
 
22
33
  # Rails 4.x does not add this helper automatically as Rails 5.X and 3.X does. So we had to created it to keep
@@ -25,23 +36,6 @@ module Nexaas
25
36
  @@nexaas_async_collector ||= Nexaas::Async::Collector::Engine.routes.url_helpers
26
37
  end
27
38
 
28
- private
29
-
30
- def validate_options(opts={})
31
- missing_keys = required_collect_opts - opts.keys.map(&:to_s)
32
- if missing_keys.any?
33
- raise "Nexaas::Async::Collector: Required parameter missing: #{missing_keys.join(', ')}"
34
- end
35
- end
36
-
37
- def collect_id
38
- @collect_id ||= SecureRandom.hex(15)
39
- end
40
-
41
- def required_collect_opts
42
- ['scope_id', 'class_name', 'class_method']
43
- end
44
-
45
39
  end
46
40
  end
47
41
  end
@@ -0,0 +1,43 @@
1
+ require 'active_model'
2
+
3
+ module Nexaas
4
+ module Async
5
+ module Collector
6
+ class AsyncResource
7
+
8
+ attr_accessor :scope_id, :class_name, :class_method, :args,
9
+ :file, :collect_id, :instrumentation_context
10
+
11
+ include ActiveModel::Validations
12
+
13
+ validates_presence_of :scope_id, :class_name, :class_method
14
+
15
+ def initialize(opts={})
16
+ opts.each do |key, value|
17
+ self.send("#{key}=", value)
18
+ end
19
+ end
20
+
21
+ def save!
22
+ initialize_collect_id
23
+ raise "Nexaas::Async::Collector: invalid fields #{errors.messages.keys.join(', ')}" unless valid?
24
+ AsyncResourceJob.perform_async(sliced_attributes)
25
+ end
26
+
27
+ def sliced_attributes
28
+ {
29
+ scope_id: scope_id, class_name: class_name, class_method: class_method,
30
+ args: args, file: file, collect_id: collect_id,
31
+ instrumentation_context: instrumentation_context
32
+ }.reject { |_,v| v.nil? }
33
+ end
34
+
35
+ private
36
+
37
+ def initialize_collect_id
38
+ @collect_id ||= SecureRandom.hex(15)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,7 +1,7 @@
1
1
  <script type="text/javascript" id="js-nexaas-async-collector-<%= unique_id %>">
2
2
  var requestContent = function() {
3
3
  $.ajax({
4
- url: '<%= nexaas_async_collector.async_resource_path(@collect_id) %>',
4
+ url: '<%= nexaas_async_collector.async_resource_path(collect_id) %>',
5
5
  dataType: 'script',
6
6
  data: { unique_id: '<%= unique_id %>' }
7
7
  })
@@ -1,7 +1,13 @@
1
1
  <% if @result.content_is_ready? %>
2
2
  clearInterval(window.nexaas_async_interval);
3
- $('#js-nexaas-async-collector-loading-<%= @unique_id %>').remove();
4
- $('#js-nexaas-async-collector-<%= @unique_id %>').parent().append("<%= escape_javascript(@result.content.html_safe) %>");
5
- $('#js-nexaas-async-collector-<%= @unique_id %>').remove()
6
- $('#js-nexaas-async-collector-style-<%= @unique_id %>').remove()
3
+
4
+ <% if @result.is_file? %>
5
+ $('#js-nexaas-async-collector-loading-<%= @unique_id %>').remove();
6
+ window.location.href = '<%= async_resource_path(params[:id], format: @result.extension) %>';
7
+ <% else %>
8
+ $('#js-nexaas-async-collector-loading-<%= @unique_id %>').remove();
9
+ $('#js-nexaas-async-collector-<%= @unique_id %>').parent().append("<%= escape_javascript(@result.content.html_safe) %>");
10
+ $('#js-nexaas-async-collector-<%= @unique_id %>').remove()
11
+ $('#js-nexaas-async-collector-style-<%= @unique_id %>').remove()
12
+ <% end %>
7
13
  <% end %>
@@ -10,12 +10,18 @@ module Nexaas
10
10
  initialize_options(opts)
11
11
  start_time = Time.current.to_i
12
12
  instrument_start(start_time)
13
- Persist.save(@scope_id, @collect_id, generate_content)
13
+ Persist.save(sliced_options(opts))
14
14
  instrument_finish(start_time)
15
15
  end
16
16
 
17
17
  private
18
18
 
19
+ def sliced_options(opts={})
20
+ opts.with_indifferent_access
21
+ .slice('collect_id', 'scope_id', 'file')
22
+ .merge('content' => generate_content)
23
+ end
24
+
19
25
  def initialize_options(opts)
20
26
  opts.each do |k, v|
21
27
  instance_variable_set("@#{k}", v)
@@ -3,19 +3,22 @@ module Nexaas
3
3
  module Collector
4
4
  class Persist
5
5
  class << self
6
- def save(scope_id, key, value)
7
- storage.set(key, content(scope_id, value))
6
+ def save(opts={})
7
+ opts = opts.with_indifferent_access
8
+ content = content_in_json(opts)
9
+ storage.set(opts[:collect_id], content)
8
10
  end
9
11
 
10
- def content(scope_id, value)
12
+ private
13
+
14
+ def content_in_json(opts)
11
15
  {
12
- 'scope_id' => scope_id,
13
- 'content' => value
16
+ 'scope_id' => opts[:scope_id],
17
+ 'content' => opts[:content],
18
+ 'file' => opts[:file]
14
19
  }.to_json
15
20
  end
16
21
 
17
- private
18
-
19
22
  def storage
20
23
  InMemoryStorage.new
21
24
  end
@@ -11,7 +11,7 @@ module Nexaas
11
11
  module Collector
12
12
  class Result
13
13
 
14
- attr_reader :scope_id, :id, :content
14
+ attr_reader :scope_id, :id, :object
15
15
 
16
16
  def initialize(scope_id, id)
17
17
  @scope_id = scope_id
@@ -19,11 +19,27 @@ module Nexaas
19
19
  end
20
20
 
21
21
  def content
22
- _content['content'] if content_is_ready?
22
+ object['content'] if content_is_ready?
23
23
  end
24
24
 
25
25
  def content_is_ready?
26
- _content && _content['scope_id'] == scope_id && _content['content']
26
+ object && object['scope_id'] == scope_id && object['content']
27
+ end
28
+
29
+ def is_file?
30
+ object && !object['file'].nil?
31
+ end
32
+
33
+ def filename
34
+ object && object.dig('file', 'name')
35
+ end
36
+
37
+ def content_type
38
+ object && object.dig('file', 'content_type')
39
+ end
40
+
41
+ def extension
42
+ object && object.dig('file', 'extension')
27
43
  end
28
44
 
29
45
  private
@@ -32,9 +48,10 @@ module Nexaas
32
48
  @storage ||= InMemoryStorage.new
33
49
  end
34
50
 
35
- def _content
36
- @_content ||= storage.get(id)
37
- @content ||= JSON.parse(@_content) if @_content
51
+ def object
52
+ return @object if @object
53
+ @_object = storage.get(id)
54
+ @object = JSON.parse(@_object) if @_object
38
55
  end
39
56
 
40
57
  def url
@@ -1,7 +1,7 @@
1
1
  module Nexaas
2
2
  module Async
3
3
  module Collector
4
- VERSION = '3.0.1'
4
+ VERSION = '3.1.0'
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexaas-async-collector
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eduardo Hertz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-20 00:00:00.000000000 Z
11
+ date: 2017-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -141,6 +141,7 @@ files:
141
141
  - app/controllers/nexaas/async/collector/application_controller.rb
142
142
  - app/controllers/nexaas/async/collector/async_resource_controller.rb
143
143
  - app/helpers/nexaas/async/collector/application_helper.rb
144
+ - app/models/nexaas/async/collector/async_resource.rb
144
145
  - app/views/nexaas/async/collector/async_resource/_loading.html.erb
145
146
  - app/views/nexaas/async/collector/async_resource/_show.html.erb
146
147
  - app/views/nexaas/async/collector/async_resource/show.js.erb