nexaas-async-collector 3.0.1 → 3.1.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
  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