felixbuenemann / xlsxtream

Streaming & Fast XLSX Spreadsheet Writer for Ruby
MIT License
217 stars 38 forks source link

How to Configure xlsxtream Properly #30

Closed zmd94 closed 6 years ago

zmd94 commented 6 years ago

Hi, I want to ask how to configure xlsxtream properly so that user can download the .xlsx file.

Firstly, what I have done is create code as below to link to export path:

<div class="float-left">
   <%= link_to "Export All", export_path, class: "btn btn-primary", target: "_blank" %>
</div>

Above code is located in my index.html.erb file.

Then, below is the code in my dashboard_controller.erb file for the export function:

def export
  @logging ||= Logging.new
  @qsos = current_user.logging.qsos

  xlsx = Xlsxtream::Workbook.new("#{current_user.callsign}.xlsx", font: { name: 'Arial', size: 11 })
  xlsx.write_worksheet 'Sheet1' do |sheet|
    sheet << ['DATE', 'TIME', 'CQ STATION', 'CALLSIGN', 'BAND', 'FREQ', 'MODE', 'RECV', 'SENT']

    @qsos.each do |qso|
      sheet << [qso.time.strftime("%Y-%m-%d"), qso.time.strftime("%H%M"), qso.logging.user.callsign.upcase, qso.callsign, qso.band, "#{(qso.frequency.to_f).round(3)} MHz", qso.mode, qso.rst_rcvd, qso.rst_sent]
    end 
  end
  xlsx.close

end

Yet, when I click the "Export All" button, it return below errors:

Sending event b88c60665d86448c802fc99aed5f4005 to Sentry
Unable to record event with remote Sentry server (Raven::Error - SSL_connect ret
urned=1 errno=0 state=error: certificate verify failed):
C:/RailsInstaller/Ruby2.3.0/lib/ruby/gems/2.3.0/gems/sentry-raven-2.7.4/lib/rave
n/transports/http.rb:34:in `rescue in send_event'
C:/RailsInstaller/Ruby2.3.0/lib/ruby/gems/2.3.0/gems/sentry-raven-2.7.4/lib/rave
n/transports/http.rb:17:in `send_event'
C:/RailsInstaller/Ruby2.3.0/lib/ruby/gems/2.3.0/gems/sentry-raven-2.7.4/lib/rave
n/client.rb:37:in `send_event'
C:/RailsInstaller/Ruby2.3.0/lib/ruby/gems/2.3.0/gems/sentry-raven-2.7.4/lib/rave
n/instance.rb:81:in `send_event'
C:/RailsInstaller/Ruby2.3.0/lib/ruby/gems/2.3.0/gems/sentry-raven-2.7.4/lib/rave
n/instance.rb:126:in `capture_type'
C:/RailsInstaller/Ruby2.3.0/lib/ruby/2.3.0/forwardable.rb:189:in `capture_type'
C:/RailsInstaller/Ruby2.3.0/lib/ruby/gems/2.3.0/gems/sentry-raven-2.7.4/lib/rave
n/integrations/rack.rb:28:in `capture_type'
C:/RailsInstaller/Ruby2.3.0/lib/ruby/gems/2.3.0/gems/sentry-raven-2.7.4/lib/rave
n/integrations/rails/overrides/debug_exceptions_catcher.rb:8:in `render_exceptio
n'
C:/RailsInstaller/Ruby2.3.0/lib/ruby/gems/2.3.0/gems/actionpack-5.2.1/lib/action
_dispatch/middleware/debug_exceptions.rb:71:in `rescue in call'
C:/RailsInstaller/Ruby2.3.0/lib/ruby/gems/2.3.0/gems/actionpack-5.2.1/lib/action
_dispatch/middleware/debug_exceptions.rb:60:in `call'
C:/RailsInstaller/Ruby2.3.0/lib/ruby/gems/2.3.0/gems/newrelic_rpm-5.3.0.346/lib/
new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
Failed to submit event: ActionController::UnknownFormat: DashboardController#exp
ort is missing a template for this request format and variant.

request.formats: ["text/html"]
request.variant: []

NOTE! For XHR/Ajax or API requests, this action would normally respond with 204
No Content: an empty white screen. Since you're loading it in a web browser, we
assume that you expected to actually render a template, not nothing, so we're sh
owing an error to be extra-clear. If you expect 204 No Content, carry on. That's
 what you'll get from an XHR or API request. Give it a shot.

ActionController::UnknownFormat (DashboardController#export is missing a templat
e for this request format and variant.

request.formats: ["text/html"]
request.variant: []

NOTE! For XHR/Ajax or API requests, this action would normally respond with 204
No Content: an empty white screen. Since you're loading it in a web browser, we
assume that you expected to actually render a template, not nothing, so we're sh
owing an error to be extra-clear. If you expect 204 No Content, carry on. That's
 what you'll get from an XHR or API request. Give it a shot.):

actionpack (5.2.1) lib/action_controller/metal/implicit_render.rb:55:in `default
_render'
actionpack (5.2.1) lib/action_controller/metal/basic_implicit_render.rb:6:in `bl
ock in send_action'
actionpack (5.2.1) lib/action_controller/metal/basic_implicit_render.rb:6:in `ta
p'
actionpack (5.2.1) lib/action_controller/metal/basic_implicit_render.rb:6:in `se
nd_action'
actionpack (5.2.1) lib/abstract_controller/base.rb:194:in `process_action'
actionpack (5.2.1) lib/action_controller/metal/rendering.rb:30:in `process_actio
n'
actionpack (5.2.1) lib/abstract_controller/callbacks.rb:42:in `block in process_
action'
activesupport (5.2.1) lib/active_support/callbacks.rb:109:in `block in run_callb
acks'
sentry-raven (2.7.4) lib/raven/integrations/rails/controller_transaction.rb:7:in
 `block in included'
activesupport (5.2.1) lib/active_support/callbacks.rb:118:in `instance_exec'
activesupport (5.2.1) lib/active_support/callbacks.rb:118:in `block in run_callb
acks'
activesupport (5.2.1) lib/active_support/callbacks.rb:136:in `run_callbacks'
actionpack (5.2.1) lib/abstract_controller/callbacks.rb:41:in `process_action'
actionpack (5.2.1) lib/action_controller/metal/rescue.rb:22:in `process_action'
actionpack (5.2.1) lib/action_controller/metal/instrumentation.rb:34:in `block i
n process_action'
activesupport (5.2.1) lib/active_support/notifications.rb:168:in `block in instr
ument'
activesupport (5.2.1) lib/active_support/notifications/instrumenter.rb:23:in `in
strument'
activesupport (5.2.1) lib/active_support/notifications.rb:168:in `instrument'
actionpack (5.2.1) lib/action_controller/metal/instrumentation.rb:32:in `process
_action'
actionpack (5.2.1) lib/action_controller/metal/params_wrapper.rb:256:in `process
_action'
activerecord (5.2.1) lib/active_record/railties/controller_runtime.rb:24:in `pro
cess_action'
actionpack (5.2.1) lib/abstract_controller/base.rb:134:in `process'
actionview (5.2.1) lib/action_view/rendering.rb:32:in `process'
actionpack (5.2.1) lib/action_controller/metal.rb:191:in `dispatch'
actionpack (5.2.1) lib/action_controller/metal.rb:252:in `dispatch'
actionpack (5.2.1) lib/action_dispatch/routing/route_set.rb:52:in `dispatch'
actionpack (5.2.1) lib/action_dispatch/routing/route_set.rb:34:in `serve'
actionpack (5.2.1) lib/action_dispatch/journey/router.rb:52:in `block in serve'
actionpack (5.2.1) lib/action_dispatch/journey/router.rb:35:in `each'
actionpack (5.2.1) lib/action_dispatch/journey/router.rb:35:in `serve'
actionpack (5.2.1) lib/action_dispatch/routing/route_set.rb:840:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
scout_apm (2.4.17) lib/scout_apm/instant/middleware.rb:53:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
scout_apm (2.4.17) lib/scout_apm/middleware.rb:17:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/rack/agent_hooks.rb:30:in `traced_call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/rack/browser_monitoring.rb:32:in `traced_
call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
warden (1.2.7) lib/warden/manager.rb:36:in `block in call'
warden (1.2.7) lib/warden/manager.rb:35:in `catch'
warden (1.2.7) lib/warden/manager.rb:35:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
rack (2.0.5) lib/rack/tempfile_reaper.rb:15:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
rack (2.0.5) lib/rack/etag.rb:25:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
rack (2.0.5) lib/rack/conditional_get.rb:25:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
rack (2.0.5) lib/rack/head.rb:12:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
actionpack (5.2.1) lib/action_dispatch/http/content_security_policy.rb:18:in `ca
ll'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
rack (2.0.5) lib/rack/session/abstract/id.rb:232:in `context'
rack (2.0.5) lib/rack/session/abstract/id.rb:226:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
actionpack (5.2.1) lib/action_dispatch/middleware/cookies.rb:670:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
activerecord (5.2.1) lib/active_record/migration.rb:559:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
actionpack (5.2.1) lib/action_dispatch/middleware/callbacks.rb:28:in `block in c
all'
activesupport (5.2.1) lib/active_support/callbacks.rb:98:in `run_callbacks'
actionpack (5.2.1) lib/action_dispatch/middleware/callbacks.rb:26:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
actionpack (5.2.1) lib/action_dispatch/middleware/executor.rb:14:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
actionpack (5.2.1) lib/action_dispatch/middleware/debug_exceptions.rb:61:in `cal
l'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
web-console (3.6.2) lib/web_console/middleware.rb:135:in `call_app'
web-console (3.6.2) lib/web_console/middleware.rb:30:in `block in call'
web-console (3.6.2) lib/web_console/middleware.rb:20:in `catch'
web-console (3.6.2) lib/web_console/middleware.rb:20:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
actionpack (5.2.1) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call
'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
railties (5.2.1) lib/rails/rack/logger.rb:38:in `call_app'
railties (5.2.1) lib/rails/rack/logger.rb:26:in `block in call'
activesupport (5.2.1) lib/active_support/tagged_logging.rb:71:in `block in tagge
d'
activesupport (5.2.1) lib/active_support/tagged_logging.rb:28:in `tagged'
activesupport (5.2.1) lib/active_support/tagged_logging.rb:71:in `tagged'
railties (5.2.1) lib/rails/rack/logger.rb:26:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
sprockets-rails (3.2.1) lib/sprockets/rails/quiet_assets.rb:13:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
actionpack (5.2.1) lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
actionpack (5.2.1) lib/action_dispatch/middleware/request_id.rb:27:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
rack (2.0.5) lib/rack/method_override.rb:22:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
rack (2.0.5) lib/rack/runtime.rb:22:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
activesupport (5.2.1) lib/active_support/cache/strategy/local_cache_middleware.r
b:29:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
actionpack (5.2.1) lib/action_dispatch/middleware/executor.rb:14:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
actionpack (5.2.1) lib/action_dispatch/middleware/static.rb:127:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
rack (2.0.5) lib/rack/sendfile.rb:111:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
sentry-raven (2.7.4) lib/raven/integrations/rack.rb:51:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
railties (5.2.1) lib/rails/engine.rb:524:in `call'
newrelic_rpm (5.3.0.346) lib/new_relic/agent/instrumentation/middleware_tracing.
rb:92:in `call'
puma (3.12.0) lib/puma/configuration.rb:225:in `call'
puma (3.12.0) lib/puma/server.rb:658:in `handle_request'
puma (3.12.0) lib/puma/server.rb:472:in `process_client'
puma (3.12.0) lib/puma/server.rb:332:in `block in run'
puma (3.12.0) lib/puma/thread_pool.rb:133:in `block in spawn_thread'

However, although there is errors, the .xlsx file still being successfully created. Yet it is in local directory. Why?

image 3 What I do wrong? Thank you.

felixbuenemann commented 6 years ago

You need to tell the controller, that it should send the file, eg.:

# after closing the xlsx
send_file "#{current_user.callsign}.xlsx",
  type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"

However it's better to write the file to a Tempfile (if it is large) or a StringIO if it is small.

If you always write to the same file, you risk file corruption if the action is called in parallel by users with the same callsign. You would also have to remove the file manually, while the Tempfile is automatically deleted after the action finishes.

Example with Tempfile:

Tempfile.open do |io|
  xlsx = Xlsxtream::Workbook.new(io)
  # write worksheet …
  xlsx.close
  send_file io.path,
    filename: "#{current_user.callsign}.xlsx",
    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
end

Example with StringIO:

io = StringIO.new
xlsx = Xlsxtream::Workbook.new(io)
# write worksheet …
xlsx.close
send_data io.string,
  filename: "#{current_user.callsign}.xlsx",
  type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
zmd94 commented 6 years ago

Many thanks Felix. I have tried the code with Tempfile, yet it is not working. So, I modify the code little bit and everything is working well now. Below if full working code:

def export
  @logging ||= Logging.new
  @qsos = current_user.logging.qsos

  tmp_file = Tempfile.new(["#{current_user.callsign}", ".xlsx"])
  Xlsxtream::Workbook.open(tmp_file.path, font: { name: 'Arial', size: 11 }) do |xlsx|
    xlsx.write_worksheet 'Sheet1' do |sheet|
      sheet << ['DATE', 'TIME', 'CQ STATION', 'CALLSIGN', 'BAND', 'FREQ', 'MODE', 'RECV', 'SENT']

      @qsos.each do |qso|
        sheet << [qso.time.strftime("%Y-%m-%d"), qso.time.strftime("%H%M"), qso.logging.user.callsign.upcase, qso.callsign, qso.band, "#{(qso.frequency.to_f).round(3)} MHz", qso.mode, qso.rst_rcvd, qso.rst_sent]
      end

    end 
  end

  send_file tmp_file,
    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
end 

Next, I suggest you to update the README.md file or I can help you. I will pull request for it.

Regards,

9W2ZOW - Malaysia.