├── .github ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── Guardfile ├── MIT-LICENSE ├── README.md ├── Rakefile ├── caxlsx_rails.gemspec ├── lib ├── axlsx_rails.rb ├── axlsx_rails │ ├── action_controller.rb │ ├── railtie.rb │ ├── template_handler.rb │ └── version.rb ├── caxlsx_rails.rb └── tasks │ └── axlsx_rails_tasks.rake └── spec ├── axlsx_builder_spec.rb ├── axlsx_mailer_spec.rb ├── axlsx_renderer_spec.rb ├── axlsx_request_spec.rb ├── gemfiles ├── Gemfile.rails-4.2 ├── Gemfile.rails-5.0 ├── Gemfile.rails-5.1 ├── Gemfile.rails-5.2 ├── Gemfile.rails-6.0 ├── Gemfile.rails-6.1 ├── Gemfile.rails-7.0 ├── Gemfile.rails-7.1 └── Gemfile.rails-7.2 ├── rails_app ├── Rakefile ├── app │ ├── assets │ │ ├── javascripts │ │ │ └── application.js │ │ └── stylesheets │ │ │ └── application.css │ ├── controllers │ │ ├── application_controller.rb │ │ ├── home_controller.rb │ │ ├── likes_controller.rb │ │ └── users_controller.rb │ ├── mailers │ │ └── notifier.rb │ ├── models │ │ ├── like.rb │ │ └── user.rb │ └── views │ │ ├── home │ │ ├── _cover_sheet.xlsx.axlsx │ │ ├── index.html.erb │ │ ├── index.xlsx.axlsx │ │ ├── only_html.html.erb │ │ ├── useheader.xlsx.axlsx │ │ └── withpartial.xlsx.axlsx │ │ ├── layouts │ │ ├── application.html.erb │ │ └── users.html.erb │ │ ├── likes │ │ ├── index.html.erb │ │ └── index.xlsx.axlsx │ │ ├── notifier │ │ ├── instructions.html.erb │ │ └── instructions.txt.erb │ │ └── users │ │ ├── export.xlsx.axlsx │ │ ├── index.html.erb │ │ ├── index.xlsx.axlsx │ │ ├── noaction.xlsx.axlsx │ │ ├── respond_with.xlsx.axlsx │ │ └── send_instructions.xlsx.axlsx ├── bin │ ├── bundle │ ├── rails │ └── rake ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── cookies_serializer.rb │ │ ├── filter_parameter_logging.rb │ │ ├── secret_token.rb │ │ ├── session_store.rb │ │ └── wrap_parameters.rb │ ├── routes.rb │ └── secrets.yml ├── db │ ├── migrate │ │ ├── 20120717192452_create_users.rb │ │ └── 20121206210955_create_likes.rb │ └── schema.rb ├── log │ └── .keep └── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ └── favicon.ico ├── spec_helper.rb └── support └── mime_type_helper.rb /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | 8 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: ['*'] 5 | pull_request: 6 | branches: ['*'] 7 | 8 | jobs: 9 | test_ruby_and_rails_versions: 10 | runs-on: ubuntu-latest 11 | 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | rails: 16 | - "4.2" 17 | - "5.0" 18 | - "5.1" 19 | - "5.2" 20 | - "6.0" 21 | - "6.1" 22 | - "7.0" 23 | - "7.1" 24 | - "7.2" 25 | 26 | ruby: 27 | - "2.4" 28 | - "2.5" 29 | - "2.6" 30 | - "2.7" 31 | - "3.0" 32 | - "3.1" 33 | - "3.2" 34 | - "3.3" 35 | 36 | include: 37 | - rails: "4.2" 38 | bundler: "1.17.3" 39 | 40 | exclude: 41 | - rails: "4.2" 42 | ruby: "2.7" 43 | 44 | - rails: "4.2" 45 | ruby: "3.0" 46 | 47 | - rails: "4.2" 48 | ruby: "3.1" 49 | 50 | - rails: "4.2" 51 | ruby: "3.2" 52 | 53 | - rails: "4.2" 54 | ruby: "3.3" 55 | 56 | - rails: "5.0" 57 | ruby: "3.0" 58 | 59 | - rails: "5.0" 60 | ruby: "3.1" 61 | 62 | - rails: "5.0" 63 | ruby: "3.2" 64 | 65 | - rails: "5.0" 66 | ruby: "3.3" 67 | 68 | - rails: "5.1" 69 | ruby: "3.0" 70 | 71 | - rails: "5.1" 72 | ruby: "3.1" 73 | 74 | - rails: "5.1" 75 | ruby: "3.2" 76 | 77 | - rails: "5.1" 78 | ruby: "3.3" 79 | 80 | - rails: "5.2" 81 | ruby: "3.0" 82 | 83 | - rails: "5.2" 84 | ruby: "3.1" 85 | 86 | - rails: "5.2" 87 | ruby: "3.2" 88 | 89 | - rails: "5.2" 90 | ruby: "3.3" 91 | 92 | - rails: "6.0" 93 | ruby: "2.4" 94 | 95 | - rails: "6.0" 96 | ruby: "3.1" 97 | 98 | - rails: "6.0" 99 | ruby: "3.2" 100 | 101 | - rails: "6.0" 102 | ruby: "3.3" 103 | 104 | - rails: "6.1" 105 | ruby: "2.4" 106 | 107 | - rails: "7.0" 108 | ruby: "2.4" 109 | 110 | - rails: "7.0" 111 | ruby: "2.5" 112 | 113 | - rails: "7.0" 114 | ruby: "2.6" 115 | 116 | - rails: "7.1" 117 | ruby: "2.4" 118 | 119 | - rails: "7.1" 120 | ruby: "2.5" 121 | 122 | - rails: "7.1" 123 | ruby: "2.6" 124 | 125 | - rails: "7.2" 126 | ruby: "2.4" 127 | 128 | - rails: "7.2" 129 | ruby: "2.5" 130 | 131 | - rails: "7.2" 132 | ruby: "2.6" 133 | 134 | - rails: "7.2" 135 | ruby: "2.7" 136 | 137 | - rails: "7.2" 138 | ruby: "3.0" 139 | 140 | env: 141 | BUNDLE_GEMFILE: ${{ github.workspace }}/spec/gemfiles/Gemfile.rails-${{ matrix.rails }} 142 | 143 | steps: 144 | - uses: actions/checkout@v4 145 | 146 | - name: Install ruby 147 | uses: ruby/setup-ruby@v1 148 | with: 149 | bundler: "${{ matrix.bundler }}" 150 | ruby-version: "${{ matrix.ruby }}" 151 | bundler-cache: true 152 | 153 | - name: Run tests 154 | run: bundle exec rspec 155 | continue-on-error: ${{ matrix.allow_failures == 'true' }} 156 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | Gemfile.lock.* 3 | .bundle/ 4 | log/*.log 5 | pkg/ 6 | spec/rails_app/db/*.sqlite3 7 | spec/rails_app/db/*.sqlite3-* 8 | spec/rails_app/log/*.log 9 | spec/rails_app/tmp/ 10 | oo_*/ 11 | tags 12 | .DS_Store 13 | tmp/ 14 | log/.keep 15 | 16 | coverage/* 17 | /.project 18 | 19 | *.sqlite3 20 | 21 | *.log 22 | 23 | *.sqlite3 24 | 25 | .ruby-version 26 | .tool-versions 27 | 28 | spec/gemfiles/*.lock 29 | .byebug_history 30 | *.gem 31 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change log 2 | 3 | **June 18, 2024**: 0.6.4 release 4 | 5 | - Convert to Github actions 6 | - Improve tests 7 | - Fix broken templates with comments as their last line 8 | 9 | **March 8, 2022**: 0.6.3 release 10 | 11 | - Exclude rspec directory (#149)[https://github.com/caxlsx/caxlsx_rails/pull/149] 12 | 13 | **December 18, 2019**: 0.6.2 release 14 | 15 | - Release under caxlsx_rails 16 | 17 | **December 18, 2019**: 0.6.1 release 18 | 19 | - Deprecate axlsx_rails name, release under caxlsx_rails 20 | - Switch to using caxlsx 3.0 gem 21 | 22 | **September 5, 2019**: 0.6.0 release 23 | 24 | - Improved Rails 6.0 compatibility re MIME type 25 | 26 | **May 1st, 2018**: 0.5.2 release 27 | 28 | - Improved Rails 5 compatibility re MIME type 29 | 30 | **March 29th, 2017**: 0.5.1 release 31 | 32 | - Fix stack trace line numbers 33 | - Thanks to [BenoitHiller](https://github.com/BenoitHiller) 34 | 35 | **July 26st, 2016**: 0.5.0 release 36 | 37 | - Support for Rails 5 38 | - **Tested on on Rails 4.0, 4.1, 4.2, and 5.0** 39 | - Bug fixes for unreadable files and UTF-8 errors 40 | 41 | **July 13th, 2015**: 0.4.0 release 42 | 43 | - Support for Rails 4.2 44 | - **Removal of forced default_formats** (url format must match) 45 | - **Tested only on Rails 4.1 and 4.2** 46 | - **For Rails 3.2 or below, use 0.3.0** 47 | 48 | **November 20th, 2014**: 0.3.0 release 49 | 50 | - Support for Rails 4.2.beta4. 51 | - **Removal of shorthand template syntax** (`render xlsx: 'another/directory'`) 52 | 53 | **September 4, 2014**: 0.2.1 release 54 | 55 | - Rails 4.2.beta1 no longer includes responder. This release checks for the existence of responder before configuring a default responder. 56 | - Rails 4.2 testing, though not yet on Travis CI 57 | - Author, created_at, and use_shared_strings parameters for Axlsx::Package.new 58 | 59 | **April 9, 2014**: 0.2.0 release 60 | 61 | - Require Axlsx 2.0.1, which requires rubyzip 1.0.0 62 | - Better render handling and testing, which might break former usage 63 | - Rails 4.1 testing 64 | - Mailer example update (**use render_to_string not render**) 65 | 66 | **October 11, 2013** 67 | 68 | - Handle (and test) respond_to override 69 | 70 | **October 4, 2013** 71 | 72 | - Added coveralls 73 | - Raised testing to axlsx 2.0.1, roo 1.12.2, and rubyzip 1.0.0 74 | 75 | **July 25, 2013** 76 | 77 | - Documentation improved 78 | - Testing for generating partial in mailer 79 | 80 | **January 18, 2013**: 0.1.4 release 81 | 82 | - Now supports Rails 4 (thanks [Envek](https://github.com/Envek)) 83 | - If you call render :xlsx on a request without :xlsx format, it should force the :xlsx format. Works on Rails 3.2+. 84 | 85 | **December 6, 2012**: 0.1.3 release 86 | 87 | - Fix for absolute template paths 88 | 89 | **July 25, 2012**: 0.1.2 release 90 | 91 | - Partials tested 92 | 93 | **July 19, 2012**: 0.1.1 release 94 | 95 | - Travis-ci added (thanks [randym](https://github.com/randym)) 96 | - render statements and filename tests fixes (thanks [engwan](https://github.com/engwan)) 97 | 98 | **July 17, 2012**: 0.1.0 release 99 | 100 | - Tests completed 101 | - Acts_as_xlsx tested, example in docs 102 | 103 | **July 12, 2012**: 0.0.1 release 104 | 105 | - Initial posting. 106 | - It works, but there are no tests! Bad programmer! 107 | 108 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | # A sample Guardfile 2 | # More info at https://github.com/guard/guard#readme 3 | 4 | guard 'rspec', :version => 2 do 5 | watch(%r{spec/.+_spec\.rb$}) 6 | watch('spec/spec_helper.rb') { "spec" } 7 | watch(%r{spec/support/.+\.rb$}) { "spec" } 8 | 9 | watch(%r{spec/dummy/app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } 10 | watch(%r{spec/dummy/app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" } 11 | watch(%r{spec/dummy/app/controllers/.+\.rb$}) { ["spec/axlsx_renderer_spec.rb", "spec/axlsx_builder_spec.rb", "axlsx_request_spec.rb"] } 12 | watch('lib/axlsx_rails/action_controller.rb') { ["spec/axlsx_renderer_spec.rb", "spec/axlsx_request_spec.rb"] } 13 | watch('lib/axlsx_rails/template_handler.rb') { "spec/axlsx_builder_spec.rb" } 14 | watch(%r{spec/dummy/app/mailers/.+\.rb$}) { "spec/axlsx_mailer_spec.rb" } 15 | watch(%r{spec/dummy/app/views/.+\.erb}) { "spec/axlsx_request_spec.rb" } 16 | end 17 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012 YOURNAME 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Notice: axlsx_rails renamed to caxlsx_rails 2 | =================================================== 3 | This gem has been renamed to match other gems in the Axlsx community organization: https://github.com/caxlsx 4 | 5 | Axlsx-Rails — Spreadsheet templates for Rails 6 | =================================================== 7 | 8 | [![Gem 9 | Version](https://badge.fury.io/rb/caxlsx_rails.svg)](https://badge.fury.io/rb/caxlsx_rails) 10 | [![Coverage 11 | Status](https://coveralls.io/repos/caxlsx/caxlsx_rails/badge.svg)](https://coveralls.io/r/caxlsx/caxlsx_rails) 12 | [![tests](https://github.com/caxlsx/caxlsx_rails/actions/workflows/test.yml/badge.svg)](https://github.com/caxlsx/caxlsx_rails/actions) 13 | ![downloads](https://img.shields.io/gem/dt/caxlsx_rails?label=downloads) 14 | 15 | ## Notice: Community Axlsx Organization 16 | 17 | To better maintain the Axlsx ecosystem, all related gems have been forked or moved to the following community organization: 18 | 19 | https://github.com/caxlsx 20 | 21 | [Join the Caxlsx Slack channel](https://join.slack.com/t/caxlsx/shared_invite/enQtOTI5OTM0MzI1Njk5LTBlMDQzNDk2YzkwODMxMmVkODMyYzJiZGU5NTQ3YTg5NTBlN2IwZTlmNTRjNzhiY2E0MDY2OTEyYmFlODI5NjA) 22 | 23 | ## Installation 24 | 25 | In your Gemfile: 26 | 27 | ```ruby 28 | gem 'caxlsx' 29 | gem 'caxlsx_rails' 30 | ``` 31 | 32 | See [previous installations](#previous-installations) if needed. 33 | 34 | ## Requirements 35 | 36 | * Tested on Rails 4.2, 5.x, 6.x, and 7.x. 37 | * For Rails 3.1 or 3.2 use version 3.0 38 | * **As of 0.5.0 requires Axlsx 2.0.1, but strongly suggests 2.1.0.pre, which requires rubyzip 1.1.0** 39 | * As of Rails 4.1 you must use `render_to_string` to render a mail attachment. 40 | 41 | ## FYI 42 | 43 | * This gem depends on [caxlsx](https://github.com/caxlsx/caxlsx). See [the blog](http://axlsx.blog.randym.net/) or the [examples page](https://github.com/caxlsx/caxlsx/tree/master/examples) for usage. 44 | * Check out [axlsx_styler](https://github.com/sakovias/axlsx_styler) by [sakovias](https://github.com/sakovias) for easier styles and borders! 45 | 46 | ## Usage 47 | 48 | Axlsx-Rails provides a renderer and a template handler. It adds the `:xlsx` format and parses `.xlsx.axlsx` templates. This lets you take all the [caxlsx](https://github.com/caxlsx/caxlsx) code out of your controller or model and place it inside the template, where view code belongs! **See [this blog post](http://axlsx.blog.randym.net/2012/08/excel-on-rails-like-pro-with-axlsxrails.html) for a more complete walkthrough.** 49 | 50 | ### Controller 51 | 52 | To use Axlsx-Rails set your instance variables in your controller and configure the response if needed: 53 | 54 | ```ruby 55 | class ButtonController < ApplicationController 56 | def action_name 57 | @buttons = Button.all 58 | respond_to do |format| 59 | format.xlsx 60 | end 61 | end 62 | end 63 | ``` 64 | 65 | ### Template 66 | 67 | Create the template with the `.xlsx.axlsx` extension (`action_name.xlsx.axlsx` for example.) [**Watch out for typos!**](#troubleshooting) In the template, use xlsx_package variable to create your spreadsheet: 68 | 69 | ```ruby 70 | wb = xlsx_package.workbook 71 | wb.add_worksheet(name: "Buttons") do |sheet| 72 | @buttons.each do |button| 73 | sheet.add_row [button.name, button.category, button.price] 74 | end 75 | end 76 | ``` 77 | 78 | This is where you place all your [caxlsx](https://github.com/caxlsx/caxlsx) specific markup. Add worksheets, fill content, merge cells, add styles. See the [caxlsx examples](https://github.com/caxlsx/caxlsx/tree/master/examples) page to see what you can do. 79 | 80 | Remember, like in `erb` templates, view helpers are available to use the `.xlsx.axlsx` template. 81 | 82 | That's it. Call your action and your spreadsheet will be delivered. 83 | 84 | ### Rendering Options 85 | 86 | You can call render in any of the following ways: 87 | 88 | ```ruby 89 | # rendered, no disposition/filename header 90 | render 'buttons' 91 | # rendered from another controller, no disposition/filename header 92 | render 'featured/latest' 93 | # template and filename of 'buttons' 94 | render xlsx: 'buttons' 95 | # template from another controller, filename of 'latest_buttons' 96 | render xlsx: 'latest_buttons', template: 'featured/latest' 97 | ``` 98 | 99 | ### Disposition 100 | 101 | To specify a disposition (such as `inline` so the spreadsheet is opened inside the browser), use the `disposition` option: 102 | 103 | ```ruby 104 | render xlsx: "buttons", disposition: 'inline' 105 | ``` 106 | 107 | If `render xlsx:` is called, the disposition defaults to `attachment`. 108 | 109 | ### File name 110 | 111 | If Rails calls Axlsx through default channels (because you use `format.xlsx {}` for example) you must set the filename using the response header: 112 | 113 | ```ruby 114 | format.xlsx { 115 | response.headers['Content-Disposition'] = 'attachment; filename="my_new_filename.xlsx"' 116 | } 117 | ``` 118 | 119 | If you use `render xlsx:` the gem will try to guess the file name: 120 | 121 | ```ruby 122 | # filename of 'buttons' 123 | render xlsx: 'buttons' 124 | # filename of 'latest_buttons' 125 | render xlsx: 'latest_buttons', template: 'featured/latest' 126 | ``` 127 | 128 | If that fails, pass the `:filename` parameter: 129 | 130 | ```ruby 131 | render xlsx: "action_or_template", filename: "my_new_filename.xlsx" 132 | ``` 133 | 134 | ### Acts As Xlsx 135 | 136 | If you use [acts_as_xlsx](https://github.com/caxlsx/acts_as_xlsx), configure the active record normally, but specify the package in the template: 137 | 138 | ```ruby 139 | User.to_xlsx package: xlsx_package, (other options) 140 | ``` 141 | 142 | **Note:** As of 4/1/2014 Acts As Xlsx is not compatible with Rails 4.1, and generates a warning on 4.0. You may use [my patched fork](https://github.com/caxlsx/acts_as_caxlsx) until it is remedied. 143 | 144 | ### Axlsx Package Options 145 | 146 | Axlsx provides three options for initializing a spreadsheet: 147 | 148 | - **:xlsx_author** (String) - The author of the document 149 | - **:xlsx_created_at** (Time) - Timestamp in the document properties (defaults to current time) 150 | - **:xlsx_use_shared_strings** (Boolean) - This is passed to the workbook to specify that shared strings should be used when serializing the package. 151 | 152 | To pass these to the new package, pass them to `render :xlsx` _or_ pass them as local variables. 153 | 154 | For example, to set the author name, pass the `:xlsx_author` parameter to `render :xlsx` _or_ as a local variable: 155 | 156 | ```ruby 157 | render xlsx: "index", xlsx_author: "Elmer Fudd" 158 | render "index", locals: {xlsx_author: "Elmer Fudd"} 159 | ``` 160 | 161 | Other examples: 162 | 163 | ```ruby 164 | render xlsx: "index", xlsx_created_at: 3.days.ago 165 | render "index", locals: {xlsx_use_shared_strings: true} 166 | ``` 167 | 168 | ### Partials 169 | 170 | Partials work as expected, but you must pass in relevant spreadsheet variables: 171 | 172 | ```ruby 173 | wb = xlsx_package.workbook 174 | render :partial => 'cover_sheet', :locals => {:wb => wb} 175 | wb.add_worksheet(name: "Content") do |sheet| 176 | sheet.add_row ['Content'] 177 | end 178 | ``` 179 | 180 | With the partial simply using the passed variables: 181 | 182 | ```ruby 183 | wb.add_worksheet(name: "Cover Sheet") do |sheet| 184 | sheet.add_row ['Cover', 'Sheet'] 185 | end 186 | ``` 187 | 188 | ### Mailers 189 | 190 | To use an xlsx template to render a mail attachment, use the following syntax: 191 | 192 | ```ruby 193 | class UserMailer < ActionMailer::Base 194 | def export(users) 195 | xlsx = render_to_string layout: false, handlers: [:axlsx], formats: [:xlsx], template: "users/export", locals: {users: users} 196 | attachment = Base64.encode64(xlsx) 197 | attachments["Users.xlsx"] = {mime_type: Mime[:xlsx], content: attachment, encoding: 'base64'} 198 | # For rails 4 use Mime::XLSX 199 | # attachments["Users.xlsx"] = {mime_type: Mime::XLSX, content: attachment, encoding: 'base64'} 200 | # self.instance_variable_set(:@_lookup_context, nil) # If attachments are rendered as content, try this and open an issue 201 | ... 202 | end 203 | end 204 | ``` 205 | 206 | * If the route specifies or suggests the `:xlsx` format you do not need to specify `formats` or `handlers`. 207 | * If the template (`users/export`) can refer to only one file (the xlsx.axlsx template), you do not need to specify `handlers`, provided the `formats` includes `:xlsx`. 208 | * Specifying the encoding as 'base64' can avoid UTF-8 errors. 209 | 210 | ### Scripts 211 | 212 | To generate a template within a script, you need to instantiate an ActionView context. Here are two gists showing how to perform this: 213 | 214 | * [Using rails runner](https://gist.github.com/straydogstudio/323139591f2cc5d48fbc) 215 | * [Without rails runner](https://gist.github.com/straydogstudio/dceb775ead81470cea70) 216 | 217 | ### Testing 218 | 219 | There is no built-in way to test your resulting workbooks / templates. But here is a piece of code that may help you to find a way. 220 | 221 | #### First, create a shared context 222 | 223 | ```ruby 224 | RSpec.shared_context 'axlsx' do 225 | 226 | # all xlsx specs describe must be normalized 227 | # "folder/view_name.xlsx.axlsx" 228 | # allow to infer the template path 229 | template_name = description 230 | 231 | let(:template_path) do 232 | ['app', 'views', template_name] 233 | end 234 | 235 | # This helper will be used in tests 236 | def render_template(locals = {}) 237 | axlsx_binding = Kernel.binding 238 | locals.each do |key, value| 239 | axlsx_binding.local_variable_set key, value 240 | end 241 | # define a default workbook and a default sheet useful when testing partial in isolation 242 | wb = Axlsx::Package.new.workbook 243 | axlsx_binding.local_variable_set(:wb, wb) 244 | axlsx_binding.local_variable_set(:sheet, wb.add_worksheet) 245 | 246 | # mimics an ActionView::Template class, presenting a 'source' method 247 | # to retrieve the content of the template 248 | filename = Rails.root.join(*template_path).to_s 249 | template = Struct.new(:source).new(File.read(filename)) 250 | axlsx_binding.eval(AxlsxRails::TemplateHandler.new.call(template), filename) 251 | axlsx_binding.local_variable_get(:wb) 252 | end 253 | end 254 | ``` 255 | 256 | #### Include it in your spec files: 257 | 258 | ```ruby 259 | require 'spec_helper' 260 | require 'helpers/axlsx_context' 261 | 262 | describe 'shared/_total_request.xlsx.axlsx' do 263 | include_context 'axlsx' 264 | 265 | before :each do 266 | # all the instance variables here are the one used in 'shared/_total_request.xlsx.axlsx' 267 | @widget = mock_model(Widget, name: 'My widget') 268 | @message_counts = Struct.new(:count_all, :positives, :negatives, :neutrals).new(42, 23, 15, 25) 269 | end 270 | 271 | it 'has a title line mentioning the widget' do 272 | wb = render_template 273 | sheet = wb.sheet_by_name('Réf. Requête') 274 | expect(sheet).to have_header_cells ['My widget : Messages de la requête'] 275 | end 276 | 277 | it 'exports the message counts' do 278 | wb = render_template 279 | sheet = wb.sheet_by_name('Réf. Requête') 280 | expect(sheet).to have_cells(['Toutes tonalités', 'Tonalité positive', 'Tonalité négative', 'Tonalité neutre']).in_row(2) 281 | expect(sheet).to have_cells([42, 23, 15, 25]).in_row(3) 282 | end 283 | 284 | end 285 | ``` 286 | 287 | #### Matchers used 288 | 289 | ```ruby 290 | 291 | # encoding: UTF-8 292 | 293 | require 'rspec/expectations' 294 | 295 | module XlsxMatchers 296 | 297 | RSpec::Matchers.define :have_header_cells do |cell_values| 298 | match do |worksheet| 299 | worksheet.rows[0].cells.map(&:value) == cell_values 300 | end 301 | 302 | failure_message do |actual| 303 | "Expected #{actual.rows[0].cells.map(&:value)} to be #{expected}" 304 | end 305 | end 306 | 307 | RSpec::Matchers.define :have_cells do |expected| 308 | match do |worksheet| 309 | worksheet.rows[@index].cells.map(&:value) == expected 310 | end 311 | 312 | chain :in_row do |index| 313 | @index = index 314 | end 315 | 316 | failure_message do |actual| 317 | "Expected #{actual.rows[@index].cells.map(&:value)} to include #{expected} at row #{@index}." 318 | end 319 | end 320 | end 321 | 322 | ``` 323 | 324 | 325 | ## Troubleshooting 326 | 327 | ### Mispellings 328 | 329 | **It is easy to get the spelling wrong in the extension name, the format.xlsx statement, or in a render call.** Here are some possibilities: 330 | 331 | * If it says your template is missing, check that its extension is `.xlsx.axlsx`. 332 | * If you get the error `uninitialized constant Mime::XSLX` you have used `format.xslx` instead of `format.xlsx`, or something similar. 333 | 334 | ### Using axlsx_rails in API mode 335 | 336 | In API mode Rails does not include ActionView, so axlsx_rails will not work. To render axlsx_rails templates you must include ActionView::Rendering in your controller and override render_to_body: 337 | 338 | ```ruby 339 | class MyController < ActionController::API 340 | include ActionView::Rendering 341 | 342 | def show 343 | respond_to do |format| 344 | format.xlsx 345 | end 346 | end 347 | 348 | private 349 | 350 | def render_to_body(options) 351 | _render_to_body_with_renderer(options) || super 352 | end 353 | end 354 | ``` 355 | 356 | See [issue 107](https://github.com/caxlsx/caxlsx_rails/issues/107) 357 | 358 | ### Mailer Attachments: No content, cannot read, Invalid Byte Sequence in UTF-8 359 | 360 | If you are having problems with rendering a template and attaching it to a template, try a few options: 361 | 362 | * Make sure the attachment template does not have the same name as the mailer. 363 | * After you have rendered the template to string, and before you call the mailer, execute `self.instance_variable_set(:@_lookup_context, nil)`. If you must do this, please open an issue. 364 | * If you get Invalid Byte Sequence in UTF-8, pass `encoding: 'base64'` with the attachment: 365 | 366 | ```ruby 367 | class UserMailer < ActionMailer::Base 368 | def export(users) 369 | xlsx = render_to_string handlers: [:axlsx], formats: [:xlsx], template: "users/export", locals: {users: users} 370 | attachments["Users.xlsx"] = {mime_type: Mime[:xlsx], content: xlsx, encoding: 'base64'} 371 | # For Rails 4 use Mime::XLSX 372 | # attachments["Users.xlsx"] = {mime_type: Mime::XLSX, content: xlsx, encoding: 'base64'} 373 | # self.instance_variable_set(:@_lookup_context, nil) # If attachments are rendered as content, try this and open an issue 374 | ... 375 | end 376 | end 377 | ``` 378 | 379 | If you get these errors, please open an issue and share code so the bug can be isolated. Or comment on issue [#29](https://github.com/caxlsx/caxlsx_rails/issues/29) or [#25](https://github.com/caxlsx/caxlsx_rails/issues/25). 380 | 381 | ### The unparsed template is returned, or something similar 382 | 383 | Have you followed other tutorials for serving Excel from Rails? Have you declared the MIME type already? These may be incompatible with caxlsx_rails (which declares the MIME type for you.) Remove any vestiges of other tutorials from your code and try again. 384 | 385 | ### Generated Files Can't Be Opened or Invalid Byte Sequence in UTF-8 386 | 387 | Both these errors *appear* to be caused by Rails applying a layout to the template. Passing `layout: false` to `render :xlsx` should fix this issue. Version 0.5.0 attempts to fix this issue. 388 | 389 | If you get this error, please open an issue and share code so the bug can be isolated. 390 | 391 | ### Rails 4.2 changes 392 | 393 | Before Rails 4.2 you could call: 394 | 395 | ```ruby 396 | render xlsx: "users/index" 397 | ``` 398 | 399 | And caxlsx_rails could adjust the paths and make sure the template was loaded from the right directory. This is no longer possible because the paths are cached between requests for a given controller. As a result, to display a template in another directory you must use the `:template` parameter (which is normal Rails behavior anyway): 400 | 401 | ```ruby 402 | render xlsx: "index", template: "users/index" 403 | ``` 404 | 405 | If the request format matches you should be able to call: 406 | 407 | ```ruby 408 | render "users/index" 409 | ``` 410 | 411 | This is a breaking change if you have the old syntax! 412 | 413 | ### Turbolinks 414 | 415 | If you are using turbolinks, you may need to disable turbolinks when you link to your spreadsheet: 416 | 417 | ```ruby 418 | # turbolinks 5: 419 | link_to 'Download spreadsheet', path_to_sheet, data: {turbolinks: false} 420 | ``` 421 | 422 | ### Rails 7 Unknown Format 423 | 424 | In Rails 7, if you get an error of "Unknown Format" you may need to add `(format: "xlsx")` to the named route. 425 | 426 | A clue to the "format" that Rails is responding with is to look at your log file or console after you click the HTML link or submit your form. You should see `Processing by Controller#action as XLSX`. 427 | 428 | #### Code Examples 429 | 430 | Scenario 1 - HTML Link within index.html.erb 431 | 432 | ```ruby 433 | link_to "Download as Excel", my_named_route_path(format: "xlsx") 434 | ``` 435 | 436 | Scenario 2 - Using form_with() 437 | 438 | ```ruby 439 | form_with method: :post, url: my_named_route_path(format: :xlsx) do |f| 440 | ``` 441 | 442 | ### What to do 443 | 444 | If you are having problems, try to isolate the issue. Use the console or a script to make sure your data is good. Then create the spreadsheet line by line without Axlsx-Rails to see if you are having caxlsx problems. If you can manually create the spreadsheet, create an issue and we will work it out. 445 | 446 | ## Previous Installations 447 | 448 | In your Gemfile: 449 | 450 | ```ruby 451 | gem 'rubyzip', '>= 1.2.1' 452 | gem 'axlsx', git: 'https://github.com/randym/axlsx.git', ref: 'c8ac844' 453 | gem 'axlsx_rails' 454 | ``` 455 | 456 | If `rubyzip 1.0.0` is needed: 457 | 458 | ```ruby 459 | gem 'rubyzip', '= 1.0.0' 460 | gem 'axlsx', '= 2.0.1' 461 | gem 'axlsx_rails' 462 | ``` 463 | 464 | If `rubyzip >= 1.1.0` is needed: 465 | 466 | ```ruby 467 | gem 'rubyzip', '~> 1.1.0' 468 | gem 'axlsx', '2.1.0.pre' 469 | gem 'axlsx_rails' 470 | ``` 471 | 472 | ## Dependencies 473 | 474 | - [Rails](https://github.com/rails/rails) 475 | - [caxlsx](https://github.com/caxlsx/caxlsx) 476 | 477 | ## Authors 478 | 479 | * [Noel Peden](https://github.com/straydogstudio) 480 | 481 | ## Contributors 482 | 483 | Many thanks to [contributors](https://github.com/caxlsx/caxlsx_rails/graphs/contributors): 484 | 485 | * [randym](https://github.com/randym) 486 | * [sugi](https://github.com/sugi) 487 | * [envek](https://github.com/envek) 488 | * [engwan](https://github.com/engwan) 489 | * [maxd](https://github.com/maxd) 490 | * [firien](https://github.com/firien) 491 | * [kaluzny](https://github.com/kaluznyo) 492 | * [sly7-7](https://github.com/sly7-7) 493 | * [kodram](https://github.com/kodram) 494 | * [JohnSmall](https://github.com/JohnSmall) 495 | * [BenoitHiller](https://github.com/BenoitHiller) 496 | 497 | ## Change log 498 | 499 | **June 18, 2024**: 0.6.4 release 500 | 501 | - Convert to Github actions 502 | - Improve tests 503 | - Fix broken templates with comments as their last line 504 | 505 | **March 8, 2022**: 0.6.3 release 506 | 507 | - Exclude rspec directory (#149)[https://github.com/caxlsx/caxlsx_rails/pull/149] 508 | 509 | **December 18, 2019**: 0.6.2 release 510 | 511 | - Release under caxlsx_rails 512 | 513 | **December 18, 2019**: 0.6.1 release 514 | 515 | - Deprecate axlsx_rails name, release under caxlsx_rails 516 | - Switch to using caxlsx 3.0 gem 517 | 518 | **September 5, 2019**: 0.6.0 release 519 | 520 | - Improved Rails 6.0 compatibility re MIME type 521 | 522 | **May 1st, 2018**: 0.5.2 release 523 | 524 | - Improved Rails 5 compatibility re MIME type 525 | 526 | **March 29th, 2017**: 0.5.1 release 527 | 528 | - Fix stack trace line numbers 529 | - Thanks to [BenoitHiller](https://github.com/BenoitHiller) 530 | 531 | **July 26st, 2016**: 0.5.0 release 532 | 533 | - Support for Rails 5 534 | - **Tested on on Rails 4.0, 4.1, 4.2, and 5.0** 535 | - Bug fixes for unreadable files and UTF-8 errors 536 | 537 | **July 13th, 2015**: 0.4.0 release 538 | 539 | - Support for Rails 4.2 540 | - **Removal of forced default_formats** (url format must match) 541 | - **Tested only on Rails 4.1 and 4.2** 542 | - **For Rails 3.2 or below, use 0.3.0** 543 | 544 | **November 20th, 2014**: 0.3.0 release 545 | 546 | - Support for Rails 4.2.beta4. 547 | - **Removal of shorthand template syntax** (`render xlsx: 'another/directory'`) 548 | 549 | **September 4, 2014**: 0.2.1 release 550 | 551 | - Rails 4.2.beta1 no longer includes responder. This release checks for the existence of responder before configuring a default responder. 552 | - Rails 4.2 testing, though not yet on Travis CI 553 | - Author, created_at, and use_shared_strings parameters for Axlsx::Package.new 554 | 555 | **April 9, 2014**: 0.2.0 release 556 | 557 | - Require Axlsx 2.0.1, which requires rubyzip 1.0.0 558 | - Better render handling and testing, which might break former usage 559 | - Rails 4.1 testing 560 | - Mailer example update (**use render_to_string not render**) 561 | 562 | **October 11, 2013** 563 | 564 | - Handle (and test) respond_to override 565 | 566 | **October 4, 2013** 567 | 568 | - Added coveralls 569 | - Raised testing to axlsx 2.0.1, roo 1.12.2, and rubyzip 1.0.0 570 | 571 | **July 25, 2013** 572 | 573 | - Documentation improved 574 | - Testing for generating partial in mailer 575 | 576 | **January 18, 2013**: 0.1.4 release 577 | 578 | - Now supports Rails 4 (thanks [Envek](https://github.com/Envek)) 579 | - If you call render :xlsx on a request without :xlsx format, it should force the :xlsx format. Works on Rails 3.2+. 580 | 581 | **December 6, 2012**: 0.1.3 release 582 | 583 | - Fix for absolute template paths 584 | 585 | **July 25, 2012**: 0.1.2 release 586 | 587 | - Partials tested 588 | 589 | **July 19, 2012**: 0.1.1 release 590 | 591 | - Travis-ci added (thanks [randym](https://github.com/randym)) 592 | - render statements and filename tests fixes (thanks [engwan](https://github.com/engwan)) 593 | 594 | **July 17, 2012**: 0.1.0 release 595 | 596 | - Tests completed 597 | - Acts_as_xlsx tested, example in docs 598 | 599 | **July 12, 2012**: 0.0.1 release 600 | 601 | - Initial posting. 602 | - It works, but there are no tests! Bad programmer! 603 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | begin 3 | require 'bundler/setup' 4 | rescue LoadError 5 | puts 'You must `gem install bundler` and `bundle install` to run rake tasks' 6 | end 7 | begin 8 | require 'rdoc/task' 9 | rescue LoadError 10 | require 'rdoc/rdoc' 11 | require 'rake/rdoctask' 12 | RDoc::Task = Rake::RDocTask 13 | end 14 | 15 | RDoc::Task.new(:rdoc) do |rdoc| 16 | rdoc.rdoc_dir = 'rdoc' 17 | rdoc.title = 'CaxlsxRails' 18 | rdoc.options << '--line-numbers' 19 | rdoc.rdoc_files.include('README.rdoc') 20 | rdoc.rdoc_files.include('lib/**/*.rb') 21 | end 22 | 23 | require "rspec/core/rake_task" 24 | RSpec::Core::RakeTask.new('spec') 25 | 26 | task :default => :spec 27 | 28 | Bundler::GemHelper.install_tasks 29 | 30 | -------------------------------------------------------------------------------- /caxlsx_rails.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'lib/axlsx_rails/version' 4 | 5 | # Describe your gem and declare its dependencies: 6 | Gem::Specification.new do |s| 7 | s.name = 'caxlsx_rails' 8 | s.version = AxlsxRails::VERSION 9 | s.licenses = ['MIT'] 10 | s.authors = ['Noel Peden'] 11 | s.email = ['noel@peden.biz'] 12 | s.homepage = 'https://github.com/caxlsx/caxlsx_rails' 13 | s.summary = 'A simple rails plugin to provide an xlsx renderer using the caxlsx gem.' 14 | s.description = "Caxlsx_Rails provides an Caxlsx renderer so you can move all your spreadsheet code from your controller into view files. Partials are supported so you can organize any code into reusable chunks (e.g. cover sheets, common styling, etc.) You can use it with acts_as_caxlsx, placing the to_xlsx call in a view and adding ':package => xlsx_package' to the parameter list. Now you can keep your controllers thin!" 15 | 16 | s.metadata = { 17 | "changelog_uri" => "https://github.com/caxlsx/caxlsx_rails/blob/master/CHANGELOG.md" 18 | } 19 | 20 | s.files = Dir['lib/**/*', 'CHANGELOG.md', 'README.md', 'MIT-LICENSE', 'caxlsx_rails.gemspec'] 21 | 22 | s.add_dependency 'actionpack', '>= 3.1' 23 | s.add_dependency 'caxlsx', '>= 3.0' 24 | 25 | s.add_development_dependency 'bundler' 26 | s.add_development_dependency 'rake' 27 | s.add_development_dependency 'rspec-rails' 28 | s.add_development_dependency 'guard-rspec' 29 | s.add_development_dependency 'capybara' 30 | s.add_development_dependency 'roo' 31 | s.add_development_dependency 'rubyzip' 32 | s.add_development_dependency 'growl' 33 | s.add_development_dependency 'rb-fsevent' 34 | s.add_development_dependency 'coveralls' 35 | s.add_development_dependency 'pry' 36 | s.add_development_dependency 'pry-nav' 37 | end 38 | -------------------------------------------------------------------------------- /lib/axlsx_rails.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | warn "DEPRECATION WARNING: axlsx_rails has been renamed to caxlsx_rails. See http://github.com/caxlsx" 4 | 5 | require 'axlsx_rails/railtie' if defined?(Rails) 6 | -------------------------------------------------------------------------------- /lib/axlsx_rails/action_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'action_controller' 4 | 5 | if Rails.version.to_f >= 5 6 | unless Mime[:xlsx] 7 | Mime::Type.register 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', :xlsx 8 | end 9 | else 10 | unless defined? Mime::XLSX 11 | Mime::Type.register 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', :xlsx 12 | end 13 | end 14 | 15 | ActionController::Renderers.add :xlsx do |filename, options| 16 | # 17 | # You can always specify a template: 18 | # 19 | # def called_action 20 | # render xlsx: 'filename', template: 'controller/diff_action' 21 | # end 22 | # 23 | # And the normal use case works: 24 | # 25 | # def called_action 26 | # render 'diff_action' 27 | # # or 28 | # render 'controller/diff_action' 29 | # end 30 | # 31 | options[:template] = filename.gsub(/^.*\//,'') if options[:template] == action_name 32 | 33 | # force layout false 34 | options[:layout] = false 35 | 36 | # disposition / filename 37 | disposition = options.delete(:disposition) || 'attachment' 38 | file_name = options.delete(:filename) || "#{filename.gsub(/^.*\//,'')}.xlsx" 39 | file_name = "#{file_name}.xlsx" unless file_name =~ /\.xlsx$/ 40 | 41 | # alternate settings 42 | options[:locals] ||= {} 43 | options[:locals][:xlsx_author] ||= options.delete(:xlsx_author) 44 | options[:locals][:xlsx_created_at] ||= options.delete(:xlsx_created_at) 45 | unless options[:locals][:xlsx_use_shared_strings] 46 | options[:locals][:xlsx_use_shared_strings] = options.delete(:xlsx_use_shared_strings) 47 | end 48 | 49 | mime = Rails.version.to_f >= 5 ? Mime[:xlsx] : Mime::XLSX 50 | send_data render_to_string(options), filename: file_name, type: mime, disposition: disposition 51 | end 52 | 53 | # For respond_to default 54 | begin 55 | ActionController::Responder 56 | rescue 57 | else 58 | class ActionController::Responder 59 | def to_xlsx 60 | @_action_has_layout = false 61 | if @default_response 62 | @default_response.call(options) 63 | else 64 | controller.render({xlsx: controller.action_name}.merge(options)) 65 | end 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lib/axlsx_rails/railtie.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'axlsx_rails/template_handler' 4 | 5 | module AxlsxRails 6 | class Railtie < Rails::Railtie 7 | initializer 'axlsx_rails.initialization' do 8 | ActiveSupport.on_load(:action_view) do 9 | ActionView::Template.register_template_handler :axlsx, AxlsxRails::TemplateHandler.new 10 | end 11 | 12 | ActiveSupport.on_load(:action_controller) do 13 | require 'axlsx_rails/action_controller' 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/axlsx_rails/template_handler.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'stringio' 4 | 5 | module AxlsxRails 6 | class TemplateHandler 7 | def default_format 8 | case 9 | when Rails.version.to_f >= 6 10 | Mime[:xlsx].symbol 11 | when Rails.version.to_f >= 5 12 | Mime[:xlsx] 13 | else 14 | Mime::XLSX 15 | end 16 | end 17 | 18 | def call(template, source = nil) 19 | builder = StringIO.new 20 | builder << "require 'axlsx';" 21 | builder << "xlsx_author = defined?(xlsx_author).nil? ? nil : xlsx_author;" 22 | builder << "xlsx_created_at = defined?(xlsx_created_at).nil? ? nil : xlsx_created_at;" 23 | builder << "xlsx_use_shared_strings = defined?(xlsx_use_shared_strings).nil? ? nil : xlsx_use_shared_strings;" 24 | builder << "xlsx_package = Axlsx::Package.new(" 25 | builder << ":author => xlsx_author," 26 | builder << ":created_at => xlsx_created_at," 27 | builder << ":use_shared_strings => xlsx_use_shared_strings);" 28 | builder << (source || template.source) 29 | builder << "\n;xlsx_package.to_stream.string;" 30 | builder.string 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/axlsx_rails/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module AxlsxRails 4 | VERSION = '0.6.4' 5 | end 6 | -------------------------------------------------------------------------------- /lib/caxlsx_rails.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'axlsx_rails/railtie' if defined?(Rails) 4 | -------------------------------------------------------------------------------- /lib/tasks/axlsx_rails_tasks.rake: -------------------------------------------------------------------------------- 1 | # desc "Explaining what the task does" 2 | # task :axlsx_rails do 3 | # # Task goes here 4 | # end 5 | -------------------------------------------------------------------------------- /spec/axlsx_builder_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe AxlsxRails::TemplateHandler do 4 | subject(:handler) { described_class.new } 5 | 6 | describe '#default_format' do 7 | it "has xlsx format" do 8 | if Rails::VERSION::MAJOR >= 6 9 | expect(handler.default_format).to eq(Mime[:xlsx].symbol) 10 | elsif Rails::VERSION::MAJOR >= 5 11 | expect(handler.default_format).to eq(Mime[:xlsx]) 12 | else 13 | expect(handler.default_format).to eq(Mime::XLSX) 14 | end 15 | end 16 | end 17 | 18 | describe 'how to compile it to an excel spreadsheet' do 19 | let(:template) { Struct.new(:source).new(template_string) } 20 | 21 | let(:template_string) { <<~RUBY } 22 | wb = xlsx_package.workbook 23 | wb.add_worksheet(name: 'Test') do |sheet| 24 | sheet.add_row ['one', 'two', 'three'] 25 | sheet.add_row ['a', 'b', 'c'] 26 | end 27 | RUBY 28 | 29 | context 'when passing in a source' do 30 | let(:source_string) { <<~RUBY } 31 | wb = xlsx_package.workbook 32 | wb.add_worksheet(name: 'Test') do |sheet| 33 | sheet.add_row ['four', 'five', 'six'] 34 | sheet.add_row ['d', 'e', 'f'] 35 | end 36 | RUBY 37 | 38 | it "compiles to an excel spreadsheet when passing in a source" do 39 | wb = nil 40 | 41 | file = Tempfile.new(['caxlsx', '.xlsx']) 42 | file.binmode 43 | file.write(eval(described_class.new.call(template, source_string))) 44 | file.close 45 | 46 | expect { wb = Roo::Excelx.new(file.path) }.to_not raise_error 47 | expect(wb.cell(2,3)).to eq('f') 48 | end 49 | end 50 | 51 | context 'when not passing in a source' do 52 | it "compiles to an excel spreadsheet when inferring source from template" do 53 | wb = nil 54 | 55 | file = Tempfile.new(['caxlsx', '.xlsx']) 56 | file.binmode 57 | file.write(eval(described_class.new.call(template))) 58 | file.close 59 | 60 | expect { wb = Roo::Excelx.new(file.path) }.to_not raise_error 61 | expect(wb.cell(2,3)).to eq('c') 62 | end 63 | 64 | context 'when template ends with a comment line' do 65 | let(:template_string) { <<~RUBY.strip } 66 | wb = xlsx_package.workbook 67 | wb.add_worksheet(name: 'Test') do |sheet| 68 | sheet.add_row ['one', 'two', 'three'] 69 | sheet.add_row ['a', 'b', 'c'] 70 | end 71 | # Extra comment 72 | RUBY 73 | 74 | it "compiles to an excel spreadsheet when inferring source from template" do 75 | wb = nil 76 | 77 | file = Tempfile.new(['caxlsx', '.xlsx']) 78 | file.binmode 79 | file.write(eval(described_class.new.call(template))) 80 | file.close 81 | 82 | expect { wb = Roo::Excelx.new(file.path) }.to_not raise_error 83 | expect(wb.cell(2,3)).to eq('c') 84 | end 85 | end 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /spec/axlsx_mailer_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "Mailer", type: :request do 4 | before :each do 5 | @user = User.create name: 'Elmer', last_name: 'Fudd', address: '1234 Somewhere, Over NY 11111', email: 'elmer@fudd.com' 6 | end 7 | 8 | it "attaches an xlsx file" do 9 | visit "/users/#{@user.id}/send_instructions" 10 | last_email = ActionMailer::Base.deliveries.last 11 | expect(last_email.to).to eq([@user.email]) 12 | expect(last_email.attachments.first).to be 13 | expect(last_email.attachments.first.content_type).to match(/#{mime_type}/) 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/axlsx_renderer_spec.rb: -------------------------------------------------------------------------------- 1 | require'spec_helper' 2 | 3 | describe 'Axlsx renderer' do 4 | 5 | it "is registered" do 6 | ActionController::Renderers::RENDERERS.include?(:xlsx) 7 | end 8 | 9 | it "has mime type" do 10 | mime = mime_type 11 | expect(mime).to be 12 | expect(mime.to_sym).to eq(:xlsx) 13 | expect(mime.to_s).to eq("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") 14 | end 15 | 16 | end -------------------------------------------------------------------------------- /spec/axlsx_request_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | describe 'Caxlsx request', :type => :request do 3 | 4 | after(:each) do 5 | if File.exist? '/tmp/caxlsx_temp.xlsx' 6 | File.unlink '/tmp/caxlsx_temp.xlsx' 7 | end 8 | end 9 | 10 | it "has a working dummy app" do 11 | User.create name: 'Elmer', last_name: 'Fudd', address: '1234 Somewhere, Over NY 11111', email: 'elmer@fudd.com' 12 | visit '/' 13 | expect(page).to have_content("Hey, you") 14 | end 15 | 16 | it "downloads an excel file from default respond_to" do 17 | visit '/home.xlsx' 18 | expect(page.response_headers['Content-Type']).to eq(mime_type.to_s + "; charset=utf-8") 19 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 20 | wb = nil 21 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to_not raise_error 22 | expect(wb.cell(2,1)).to eq('Untie!') 23 | end 24 | 25 | it "downloads an excel file from respond_to while specifying filename" do 26 | visit '/useheader.xlsx' 27 | 28 | expect(page.response_headers['Content-Type']).to eq(mime_type.to_s) 29 | expect(page.response_headers['Content-Disposition']).to include("filename=\"filename_test.xlsx\"") 30 | 31 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 32 | wb = nil 33 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to_not raise_error 34 | expect(wb.cell(2,1)).to eq('Untie!') 35 | end 36 | 37 | it "downloads an excel file from respond_to while specifying filename in direct format" do 38 | visit '/useheader.xlsx?set_direct=true' 39 | 40 | expect(page.response_headers['Content-Type']).to eq(mime_type.to_s + "; charset=utf-8") 41 | expect(page.response_headers['Content-Disposition']).to include("filename=\"filename_test.xlsx\"") 42 | 43 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 44 | wb = nil 45 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to_not raise_error 46 | expect(wb.cell(2,1)).to eq('Untie!') 47 | end 48 | 49 | it "downloads an excel file from render statement with filename" do 50 | visit '/another.xlsx' 51 | 52 | expect(page.response_headers['Content-Type']).to eq(mime_type) 53 | expect(page.response_headers['Content-Disposition']).to include("filename=\"filename_test.xlsx\"") 54 | 55 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 56 | wb = nil 57 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to_not raise_error 58 | expect(wb.cell(2,1)).to eq('Untie!') 59 | end 60 | 61 | it "downloads an excel file from acts_as_xlsx model" do 62 | User.destroy_all 63 | User.create name: 'Elmer', last_name: 'Fudd', address: '1234 Somewhere, Over NY 11111', email: 'elmer@fudd.com' 64 | User.create name: 'Bugs', last_name: 'Bunny', address: '1234 Left Turn, Albuquerque NM 22222', email: 'bugs@bunny.com' 65 | visit '/users.xlsx' 66 | expect(page.response_headers['Content-Type']).to eq(mime_type.to_s + "; charset=utf-8") 67 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 68 | wb = nil 69 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to_not raise_error 70 | expect(wb.cell(3,2)).to eq('Bugs') 71 | end 72 | 73 | it "downloads an excel file with partial" do 74 | visit '/withpartial.xlsx' 75 | expect(page.response_headers['Content-Type']).to eq(mime_type.to_s + "; charset=utf-8") 76 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 77 | wb = nil 78 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to_not raise_error 79 | expect(wb.cell(1,1,wb.sheets[0])).to eq('Cover') 80 | expect(wb.cell(2,1,wb.sheets[1])).to eq("Untie!") 81 | end 82 | 83 | it "handles nested resources" do 84 | User.destroy_all 85 | @user = User.create name: 'Bugs', last_name: 'Bunny', address: '1234 Left Turn, Albuquerque NM 22222', email: 'bugs@bunny.com' 86 | @user.likes.create(:name => 'Carrots') 87 | @user.likes.create(:name => 'Celery') 88 | visit "/users/#{@user.id}/likes.xlsx" 89 | expect(page.response_headers['Content-Type']).to eq(mime_type.to_s + "; charset=utf-8") 90 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 91 | wb = nil 92 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to_not raise_error 93 | expect(wb.cell(1,1)).to eq('Bugs') 94 | expect(wb.cell(2,1)).to eq('Carrots') 95 | expect(wb.cell(3,1)).to eq('Celery') 96 | end 97 | 98 | it "handles reference to absolute paths" do 99 | User.destroy_all 100 | @user = User.create name: 'Bugs', last_name: 'Bunny', address: '1234 Left Turn, Albuquerque NM 22222', email: 'bugs@bunny.com' 101 | visit "/users/#{@user.id}/render_elsewhere.xlsx" 102 | expect(page.response_headers['Content-Type']).to eq(mime_type.to_s) 103 | [[1,false],[3,true],[4,true],[5,false]].reverse.each do |s| 104 | visit "/home/render_elsewhere.xlsx?type=#{s[0]}" 105 | expect(page.response_headers['Content-Type']).to eq(mime_type.to_s + (s[1] ? "; charset=utf-8" : '')) 106 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 107 | wb = nil 108 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to_not raise_error 109 | if s[0] == 5 110 | expect(wb.cell(1,1)).to eq('Bad') 111 | else 112 | expect(wb.cell(2,2)).to eq('Bugs') 113 | end 114 | end 115 | end 116 | 117 | it "uses respond_with" do 118 | User.destroy_all 119 | @user = User.create name: 'Responder', last_name: 'Bunny', address: '1234 Right Turn, Albuquerque NM 22222', email: 'bugs@bunny.com' 120 | visit "/users/#{@user.id}.xlsx" 121 | expect { 122 | visit "/users/#{@user.id}.xlsx" 123 | }.to_not raise_error 124 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 125 | wb = nil 126 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to_not raise_error 127 | expect(wb.cell(2,1)).to eq('Untie!') 128 | end 129 | 130 | it "ignores layout" do 131 | User.destroy_all 132 | @user = User.create name: 'Responder', last_name: 'Bunny', address: '1234 Right Turn, Albuquerque NM 22222', email: 'bugs@bunny.com' 133 | expect { 134 | visit "/users/export/#{@user.id}.xlsx" 135 | }.to_not raise_error 136 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 137 | wb = nil 138 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to_not raise_error 139 | expect(wb.cell(2,1)).to eq('Untie!') 140 | end 141 | 142 | it "handles missing format with render :xlsx" do 143 | visit '/another' 144 | 145 | expect(page.response_headers['Content-Type']).to eq(mime_type) 146 | expect(page.response_headers['Content-Disposition']).to include("filename=\"filename_test.xlsx\"") 147 | 148 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 149 | wb = nil 150 | # wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') 151 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to raise_error(Zip::ZipError) 152 | # wb.cell(2,1).should == 'Untie!' 153 | end 154 | 155 | if Rails.version > '4.0' && Rails.version < '5.0' 156 | Capybara.register_driver :mime_all do |app| 157 | Capybara::RackTest::Driver.new(app, headers: { 'HTTP_ACCEPT' => '*/*' }) 158 | end 159 | 160 | def puts_def_formats(title) 161 | puts "default formats #{title.ljust(30)}: #{ActionView::Base.default_formats}" 162 | end 163 | 164 | it "mime all with render :xlsx and then :html" do 165 | # puts_def_formats 'before' 166 | ActionView::Base.default_formats.delete :xlsx # see notes 167 | # puts_def_formats 'in my project' 168 | Capybara.current_driver = :mime_all 169 | visit '/another' 170 | # puts_def_formats 'after render xlsx with */*' 171 | expect{ 172 | visit '/home/only_html' 173 | }.to_not raise_error 174 | ActionView::Base.default_formats.push :xlsx # see notes 175 | 176 | # Output: 177 | # default formats before : [:html, :text, :js, :css, :ics, :csv, :vcf, :png, :jpeg, :gif, :bmp, :tiff, :mpeg, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json, :pdf, :zip, :xlsx] 178 | # default formats in my project : [:html, :text, :js, :css, :ics, :csv, :vcf, :png, :jpeg, :gif, :bmp, :tiff, :mpeg, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json, :pdf, :zip] 179 | # default formats after render xlsx with */* : [:xlsx, :text, :js, :css, :ics, :csv, :vcf, :png, :jpeg, :gif, :bmp, :tiff, :mpeg, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json, :pdf, :zip] 180 | 181 | # Failure/Error: visit '/home/only_html' 182 | # ActionView::MissingTemplate: 183 | # Missing template home/only_html, application/only_html with {:locale=>[:en], :formats=>[:xlsx, :text, :js, :css, :ics, :csv, :vcf, :png, :jpeg, :gif, :bmp, :tiff, :mpeg, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json, :pdf, :zip], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :axlsx]}. 184 | end 185 | end 186 | 187 | if Rails::VERSION::MAJOR < 6 188 | it "downloads an excel file when there is no action" do 189 | User.destroy_all 190 | User.create name: 'Elmer', last_name: 'Fudd', address: '1234 Somewhere, Over NY 11111', email: 'elmer@fudd.com' 191 | User.create name: 'Bugs', last_name: 'Bunny', address: '1234 Left Turn, Albuquerque NM 22222', email: 'bugs@bunny.com' 192 | visit '/users/noaction.xlsx' 193 | expect(page.response_headers['Content-Type']).to eq(mime_type.to_s + "; charset=utf-8") 194 | File.open('/tmp/caxlsx_temp.xlsx', 'wb') {|f| f.write(page.source) } 195 | wb = nil 196 | expect{ wb = Roo::Excelx.new('/tmp/caxlsx_temp.xlsx') }.to_not raise_error 197 | expect(wb.cell(3,2)).to eq('Bugs') 198 | end 199 | end 200 | end 201 | -------------------------------------------------------------------------------- /spec/gemfiles/Gemfile.rails-4.2: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec path: '../../' 4 | 5 | gem 'rails', "~> 4.2.0" 6 | gem 'responders', '~> 2.0' 7 | gem 'sqlite3', '1.3.13' 8 | gem 'sprockets', '~> 3.0' 9 | gem "jquery-rails" 10 | gem "thin" 11 | gem 'capybara', '~> 2.1' 12 | gem 'acts_as_caxlsx', git: 'https://github.com/caxlsx/acts_as_caxlsx.git' 13 | 14 | gem 'byebug' 15 | 16 | if RUBY_VERSION < '2.5' 17 | gem 'loofah', '< 2.21.0' 18 | end 19 | 20 | gem 'bigdecimal', '~> 1.4' 21 | gem 'ffi', '< 1.17.0' 22 | -------------------------------------------------------------------------------- /spec/gemfiles/Gemfile.rails-5.0: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec path: '../../' 4 | 5 | gem 'rails', "~> 5.0.0" 6 | gem 'responders', '~> 2.0' 7 | gem 'sqlite3', '~> 1.3.6' 8 | gem 'sprockets', '~> 3.0' 9 | gem "jquery-rails" 10 | gem "thin" 11 | gem 'capybara', '~> 2.1' 12 | gem 'acts_as_caxlsx', git: 'https://github.com/caxlsx/acts_as_caxlsx.git' 13 | 14 | gem 'byebug' 15 | 16 | if RUBY_VERSION < '2.5' 17 | gem 'loofah', '< 2.21.0' 18 | end 19 | -------------------------------------------------------------------------------- /spec/gemfiles/Gemfile.rails-5.1: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec path: '../../' 4 | 5 | gem 'rails', "~> 5.1.0" 6 | gem 'responders', '~> 3.0' 7 | gem 'sqlite3', '~> 1.4.4' 8 | gem 'sprockets', '~> 3.0' 9 | gem "jquery-rails" 10 | gem "thin" 11 | gem 'capybara', '~> 2.1' 12 | gem 'acts_as_caxlsx', git: 'https://github.com/caxlsx/acts_as_caxlsx.git' 13 | 14 | gem 'byebug' 15 | 16 | if RUBY_VERSION < '2.5' 17 | gem 'loofah', '< 2.21.0' 18 | end 19 | -------------------------------------------------------------------------------- /spec/gemfiles/Gemfile.rails-5.2: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec path: '../../' 4 | 5 | gem 'rails', "~> 5.2.0" 6 | gem 'responders', '~> 3.0' 7 | gem 'sqlite3', '~> 1.4.4' 8 | gem 'sprockets', '~> 3.0' 9 | gem "jquery-rails" 10 | gem "thin" 11 | gem 'capybara', '~> 2.1' 12 | gem 'acts_as_caxlsx', git: 'https://github.com/caxlsx/acts_as_caxlsx.git' 13 | 14 | gem 'byebug' 15 | 16 | if RUBY_VERSION < '2.5' 17 | gem 'loofah', '< 2.21.0' 18 | end 19 | -------------------------------------------------------------------------------- /spec/gemfiles/Gemfile.rails-6.0: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec path: '../../' 4 | 5 | gem 'rails', "~> 6.0.0" 6 | gem 'responders', '~> 3.0' 7 | gem 'sqlite3', '~> 1.4' 8 | gem 'sprockets', '~> 3.0' 9 | gem "jquery-rails" 10 | gem "thin" 11 | gem 'capybara', '~> 2.1' 12 | gem 'acts_as_caxlsx', git: 'https://github.com/caxlsx/acts_as_caxlsx.git' 13 | 14 | gem 'byebug' 15 | 16 | gem 'concurrent-ruby', '< 1.3.5' 17 | -------------------------------------------------------------------------------- /spec/gemfiles/Gemfile.rails-6.1: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec path: '../../' 4 | 5 | gem 'rails', "~> 6.1.0" 6 | gem 'responders', '~> 3.0' 7 | gem 'sqlite3', '~> 1.4' 8 | gem 'sprockets', '~> 3.0' 9 | gem "jquery-rails" 10 | gem "thin" 11 | gem 'capybara', '~> 2.1' 12 | gem 'acts_as_caxlsx', git: 'https://github.com/caxlsx/acts_as_caxlsx.git' 13 | 14 | gem 'byebug' 15 | 16 | gem 'concurrent-ruby', '< 1.3.5' 17 | -------------------------------------------------------------------------------- /spec/gemfiles/Gemfile.rails-7.0: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec path: '../../' 4 | 5 | gem 'rails', "~> 7.0.0" 6 | gem 'responders', '~> 3.0' 7 | gem 'sqlite3', '~> 1.4' 8 | gem 'sprockets', '~> 3.0' 9 | gem "jquery-rails" 10 | gem "thin" 11 | gem 'capybara', '~> 2.1' 12 | gem 'acts_as_caxlsx', git: 'https://github.com/caxlsx/acts_as_caxlsx.git' 13 | 14 | gem 'byebug' 15 | 16 | gem 'concurrent-ruby', '< 1.3.5' 17 | -------------------------------------------------------------------------------- /spec/gemfiles/Gemfile.rails-7.1: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec path: '../../' 4 | 5 | gem 'rails', '~> 7.1.0' 6 | gem 'responders', '~> 3.0' 7 | gem 'sqlite3' 8 | gem 'sprockets', '~> 4.0' 9 | gem 'jquery-rails' 10 | gem 'thin' 11 | gem 'capybara', '~> 3.0' 12 | gem 'acts_as_caxlsx', git: 'https://github.com/caxlsx/acts_as_caxlsx.git' 13 | 14 | gem 'byebug' 15 | -------------------------------------------------------------------------------- /spec/gemfiles/Gemfile.rails-7.2: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec path: '../../' 4 | 5 | gem 'rails', '~> 7.2.0' 6 | gem 'responders', '~> 3.0' 7 | gem 'sqlite3' 8 | gem 'sprockets', '~> 4.0' 9 | gem 'jquery-rails' 10 | gem 'thin' 11 | gem 'capybara', '~> 3.0' 12 | gem 'acts_as_caxlsx', git: 'https://github.com/caxlsx/acts_as_caxlsx.git' 13 | 14 | gem 'byebug' 15 | -------------------------------------------------------------------------------- /spec/rails_app/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /spec/rails_app/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require_tree . 14 | -------------------------------------------------------------------------------- /spec/rails_app/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any styles 10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new 11 | * file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /spec/rails_app/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Prevent CSRF attacks by raising an exception. 3 | # For APIs, you may want to use :null_session instead. 4 | protect_from_forgery with: :exception 5 | end 6 | -------------------------------------------------------------------------------- /spec/rails_app/app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | #--- 2 | # Excerpted from "Crafting Rails Applications", 3 | # published by The Pragmatic Bookshelf. 4 | # Copyrights apply to this code. It may not be used to create training material, 5 | # courses, books, articles, and the like. Contact us if you are in doubt. 6 | # We make no guarantees that this code is fit for any purpose. 7 | # Visit http://www.pragmaticprogrammer.com/titles/jvrails for more book information. 8 | #--- 9 | class HomeController < ApplicationController 10 | def index 11 | respond_to do |format| 12 | format.html 13 | format.xlsx 14 | end 15 | end 16 | 17 | def only_html; end 18 | 19 | def another 20 | render :xlsx => "index", :filename => "filename_test.xlsx" 21 | end 22 | 23 | def render_elsewhere 24 | case params[:type] 25 | when '1' 26 | render :xlsx => "home/index", :template => 'users/index' 27 | when '2' 28 | render :xlsx => "users/index", :template => 'users/index' 29 | when '3' 30 | render template: "users/index" 31 | when '4' 32 | render "users/index" 33 | else 34 | render :xlsx => "index" 35 | end 36 | end 37 | 38 | def render_file_path 39 | render :xlsx => Rails.root.join('app','views','users','index') 40 | end 41 | 42 | def withpartial 43 | end 44 | 45 | def useheader 46 | respond_to do |format| 47 | format.xlsx { 48 | if params[:set_direct] 49 | response.headers['Content-Disposition'] = "attachment; filename=\"filename_test.xlsx\"" 50 | else 51 | render xlsx: "useheader", filename: "filename_test.xlsx" 52 | end 53 | } 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /spec/rails_app/app/controllers/likes_controller.rb: -------------------------------------------------------------------------------- 1 | class LikesController < ApplicationController 2 | # GET /likes 3 | # GET /likes.json 4 | def index 5 | @user = User.find(params[:user_id]) 6 | @likes = @user.likes 7 | 8 | respond_to do |format| 9 | format.html # index.html.erb 10 | format.xlsx 11 | end 12 | end 13 | 14 | def render_elsewhere 15 | @user = User.find(params[:user_id]) 16 | render :xlsx => "index", :template => 'users/index' 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/rails_app/app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | respond_to :xlsx, :html 3 | 4 | if Gem::Version.new("5.0") <= Rails.gem_version 5 | layout Proc.new { |c| return (c.request.format.symbol == :xlsx ? false : :default )} 6 | end 7 | 8 | # GET /users 9 | # GET /users.json 10 | def index 11 | @users = User.all 12 | 13 | respond_to do |format| 14 | format.html # index.html.erb 15 | format.xlsx 16 | end 17 | end 18 | 19 | def show 20 | @user = User.find(params[:id]) 21 | respond_with(@user) do |format| 22 | if Gem::Version.new("7.0") <= Rails.gem_version 23 | format.xlsx { render "respond_with" } 24 | else 25 | format.xlsx { render "respond_with.xlsx.axlsx" } 26 | end 27 | end 28 | end 29 | 30 | def send_instructions 31 | @user = User.find(params[:user_id]) 32 | @user.send_instructions 33 | if Rails.gem_version < Gem::Version.new("5.0") 34 | render text: "Email sent" 35 | else 36 | render plain: "Email sent" 37 | end 38 | end 39 | 40 | def export 41 | @user = User.find(params[:id]) 42 | respond_to do |format| 43 | format.xlsx do 44 | render xlsx: "export", filename: "export_#{@user.id}" 45 | end 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/rails_app/app/mailers/notifier.rb: -------------------------------------------------------------------------------- 1 | class Notifier < ActionMailer::Base 2 | default :from => 'noreply@company.com' 3 | 4 | def instructions(user) 5 | @user = user 6 | 7 | # normal syntax 8 | xlsx = render_to_string handlers: [:axlsx], template: 'users/send_instructions', layout: false, formats: [:xlsx] 9 | if Rails.gem_version < Gem::Version.new("5.0") 10 | attachments["user_#{user.id}.xlsx"] = {mime_type: Mime::XLSX, content: xlsx} 11 | else 12 | attachments["user_#{user.id}.xlsx"] = {mime_type: Mime[:xlsx], content: xlsx} 13 | end 14 | 15 | mail :to => user.email, :subject => 'Instructions' 16 | end 17 | 18 | end -------------------------------------------------------------------------------- /spec/rails_app/app/models/like.rb: -------------------------------------------------------------------------------- 1 | class Like < ActiveRecord::Base 2 | belongs_to :user 3 | end 4 | -------------------------------------------------------------------------------- /spec/rails_app/app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | acts_as_xlsx columns: [:id, :name, :last_name, :address, :email] 3 | 4 | has_many :likes 5 | 6 | def send_instructions 7 | Notifier.instructions(self).deliver 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/rails_app/app/views/home/_cover_sheet.xlsx.axlsx: -------------------------------------------------------------------------------- 1 | wb.add_worksheet(name: "Cover Sheet") do |sheet| 2 | sheet.add_row ['Cover', 'Sheet'] 3 | end -------------------------------------------------------------------------------- /spec/rails_app/app/views/home/index.html.erb: -------------------------------------------------------------------------------- 1 |

Hey, you can download the xlsx for this page by clicking the link below:

2 |

<%= link_to "XLSX", home_path("xlsx") %>

3 |

<%= link_to "Another", '/another.xlsx' %>

4 |

<%= link_to "User header", '/useheader.xlsx' %>

5 | -------------------------------------------------------------------------------- /spec/rails_app/app/views/home/index.xlsx.axlsx: -------------------------------------------------------------------------------- 1 | wb = xlsx_package.workbook 2 | style_shout = wb.styles.add_style sz: 16, b: true, alignment: { horizontal: :center } 3 | wb.add_worksheet(name: "Foobar") do |sheet| 4 | sheet.add_row ['Bad', 'spellers', 'of', 'the', 'world', '...'] 5 | sheet.add_row ['Untie!'] 6 | sheet.merge_cells("A2:E2") 7 | sheet["A2"].style = style_shout 8 | end -------------------------------------------------------------------------------- /spec/rails_app/app/views/home/only_html.html.erb: -------------------------------------------------------------------------------- 1 |

Foo, bar

2 | -------------------------------------------------------------------------------- /spec/rails_app/app/views/home/useheader.xlsx.axlsx: -------------------------------------------------------------------------------- 1 | wb = xlsx_package.workbook 2 | style_shout = wb.styles.add_style sz: 16, b: true, alignment: { horizontal: :center } 3 | wb.add_worksheet(name: "Foobar") do |sheet| 4 | sheet.add_row ['Bad', 'spellers', 'of', 'the', 'world', '...'] 5 | sheet.add_row ['Untie!'] 6 | sheet.merge_cells("A2:E2") 7 | sheet["A2"].style = style_shout 8 | end -------------------------------------------------------------------------------- /spec/rails_app/app/views/home/withpartial.xlsx.axlsx: -------------------------------------------------------------------------------- 1 | wb = xlsx_package.workbook 2 | render :partial => 'cover_sheet', :locals => {:wb => wb} 3 | style_shout = wb.styles.add_style sz: 16, b: true, alignment: { horizontal: :center } 4 | wb.add_worksheet(name: "Foobar") do |sheet| 5 | sheet.add_row ['Bad', 'spellers', 'of', 'the', 'world', '...'] 6 | sheet.add_row ['Untie!'] 7 | sheet.merge_cells("A2:E2") 8 | sheet["A2"].style = style_shout 9 | end -------------------------------------------------------------------------------- /spec/rails_app/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 4 5 | <%= csrf_meta_tags %> 6 | 7 | 8 | 9 | <%= yield %> 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /spec/rails_app/app/views/layouts/users.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Dummy 4 5 | <%= csrf_meta_tags %> 6 | 7 | 8 | 9 | <%= yield %> 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /spec/rails_app/app/views/likes/index.html.erb: -------------------------------------------------------------------------------- 1 |

Listing likes for <%= @user.name %>

2 | 3 | 4 | 5 | 6 | 7 | 8 | <% @likes.each do |like| %> 9 | 10 | 11 | 12 | <% end %> 13 |
Name
<%= like.name %>
14 | 15 |
16 | 17 | <%= link_to 'New Like', new_like_path %> 18 | -------------------------------------------------------------------------------- /spec/rails_app/app/views/likes/index.xlsx.axlsx: -------------------------------------------------------------------------------- 1 | wb = xlsx_package.workbook 2 | wb.add_worksheet(name: "Foobar") do |sheet| 3 | sheet.add_row [@user.name] 4 | @likes.each do |like| 5 | sheet.add_row [like.name] 6 | end 7 | end -------------------------------------------------------------------------------- /spec/rails_app/app/views/notifier/instructions.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |

Instructions

8 |

9 | You have successfully signed up to example.com, 10 | your username is: <%= @user.email %>.
11 |

12 |

Thanks for joining and have a great day!

13 | 14 | 15 | -------------------------------------------------------------------------------- /spec/rails_app/app/views/notifier/instructions.txt.erb: -------------------------------------------------------------------------------- 1 | Instructions 2 | 3 | You have successfully signed up to example.com, 4 | your username is: <%= @user.email %>. 5 | 6 | Thanks for joining and have a great day! 7 | -------------------------------------------------------------------------------- /spec/rails_app/app/views/users/export.xlsx.axlsx: -------------------------------------------------------------------------------- 1 | wb = xlsx_package.workbook 2 | style_shout = wb.styles.add_style sz: 16, b: true, alignment: { horizontal: :center } 3 | wb.add_worksheet(name: "Foobar") do |sheet| 4 | sheet.add_row ['Bad', 'spellers', 'of', 'the', 'world', '...'] 5 | sheet.add_row ['Untie!'] 6 | sheet.merge_cells("A2:E2") 7 | sheet["A2"].style = style_shout 8 | end -------------------------------------------------------------------------------- /spec/rails_app/app/views/users/index.html.erb: -------------------------------------------------------------------------------- 1 |

Listing users

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | <% @users.each do |user| %> 12 | 13 | 14 | 15 | 16 | 17 | 18 | <% end %> 19 |
NameLast nameAddressEmail
<%= user.name %><%= user.last_name %><%= user.address %><%= user.email %>
20 | 21 |
22 | 23 | <%= link_to 'New User', new_user_path %> 24 | -------------------------------------------------------------------------------- /spec/rails_app/app/views/users/index.xlsx.axlsx: -------------------------------------------------------------------------------- 1 | User.to_xlsx package: xlsx_package 2 | -------------------------------------------------------------------------------- /spec/rails_app/app/views/users/noaction.xlsx.axlsx: -------------------------------------------------------------------------------- 1 | User.to_xlsx package: xlsx_package 2 | -------------------------------------------------------------------------------- /spec/rails_app/app/views/users/respond_with.xlsx.axlsx: -------------------------------------------------------------------------------- 1 | wb = xlsx_package.workbook 2 | style_shout = wb.styles.add_style sz: 16, b: true, alignment: { horizontal: :center } 3 | wb.add_worksheet(name: "Foobar") do |sheet| 4 | sheet.add_row ['Bad', 'spellers', 'of', 'the', 'world', '...'] 5 | sheet.add_row ['Untie!'] 6 | sheet.merge_cells("A2:E2") 7 | sheet["A2"].style = style_shout 8 | end -------------------------------------------------------------------------------- /spec/rails_app/app/views/users/send_instructions.xlsx.axlsx: -------------------------------------------------------------------------------- 1 | wb = xlsx_package.workbook 2 | wb.add_worksheet(name: "Instructions") do |sheet| 3 | sheet.add_row [@user.id, @user.name, @user.email] 4 | sheet.add_row ['', 'Instructions', ''] 5 | end 6 | -------------------------------------------------------------------------------- /spec/rails_app/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /spec/rails_app/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /spec/rails_app/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /spec/rails_app/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /spec/rails_app/config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | Bundler.require(*Rails.groups) 6 | 7 | module Dummy 8 | class Application < Rails::Application 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /spec/rails_app/config/boot.rb: -------------------------------------------------------------------------------- 1 | # Set up gems listed in the Gemfile. 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) 3 | 4 | require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) 5 | $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) 6 | -------------------------------------------------------------------------------- /spec/rails_app/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /spec/rails_app/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /spec/rails_app/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports and disable caching. 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send. 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger. 20 | config.active_support.deprecation = :log 21 | 22 | # Raise an error on page load if there are pending migrations. 23 | config.active_record.migration_error = :page_load 24 | 25 | # Debug mode disables concatenation and preprocessing of assets. 26 | # This option may cause significant delays in view rendering with a large 27 | # number of complex assets. 28 | config.assets.debug = true 29 | 30 | # Adds additional error checking when serving assets at runtime. 31 | # Checks for improperly declared sprockets dependencies. 32 | # Raises helpful error messages. 33 | config.assets.raise_runtime_errors = true 34 | 35 | # Raises error for missing translations 36 | # config.action_view.raise_on_missing_translations = true 37 | end 38 | -------------------------------------------------------------------------------- /spec/rails_app/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. 20 | # config.action_dispatch.rack_cache = true 21 | 22 | # Disable Rails's static asset server (Apache or nginx will already do this). 23 | config.serve_static_assets = false 24 | 25 | # Compress JavaScripts and CSS. 26 | config.assets.js_compressor = :uglifier 27 | # config.assets.css_compressor = :sass 28 | 29 | # Do not fallback to assets pipeline if a precompiled asset is missed. 30 | config.assets.compile = false 31 | 32 | # Generate digests for assets URLs. 33 | config.assets.digest = true 34 | 35 | # Version of your assets, change this if you want to expire all your assets. 36 | config.assets.version = '1.0' 37 | 38 | # Specifies the header that your server uses for sending files. 39 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 40 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 41 | 42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 43 | # config.force_ssl = true 44 | 45 | # Set to :debug to see everything in the log. 46 | config.log_level = :info 47 | 48 | # Prepend all log lines with the following tags. 49 | # config.log_tags = [ :subdomain, :uuid ] 50 | 51 | # Use a different logger for distributed setups. 52 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 53 | 54 | # Use a different cache store in production. 55 | # config.cache_store = :mem_cache_store 56 | 57 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 58 | # config.action_controller.asset_host = "http://assets.example.com" 59 | 60 | # Precompile additional assets. 61 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 62 | # config.assets.precompile += %w( search.js ) 63 | 64 | # Ignore bad email addresses and do not raise email delivery errors. 65 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 66 | # config.action_mailer.raise_delivery_errors = false 67 | 68 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 69 | # the I18n.default_locale when a translation cannot be found). 70 | config.i18n.fallbacks = true 71 | 72 | # Send deprecation notices to registered listeners. 73 | config.active_support.deprecation = :notify 74 | 75 | # Disable automatic flushing of the log to improve performance. 76 | # config.autoflush_log = false 77 | 78 | # Use default logging formatter so that PID and timestamp are not suppressed. 79 | config.log_formatter = ::Logger::Formatter.new 80 | 81 | # Do not dump schema after migrations. 82 | config.active_record.dump_schema_after_migration = false 83 | end 84 | -------------------------------------------------------------------------------- /spec/rails_app/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | #Rails.application.configure do 2 | Dummy::Application.configure do 3 | # Settings specified here will take precedence over those in config/application.rb. 4 | 5 | # The test environment is used exclusively to run your application's 6 | # test suite. You never need to work with it otherwise. Remember that 7 | # your test database is "scratch space" for the test suite and is wiped 8 | # and recreated between test runs. Don't rely on the data there! 9 | config.cache_classes = true 10 | 11 | # Do not eager load code on boot. This avoids loading your whole application 12 | # just for the purpose of running a single test. If you are using a tool that 13 | # preloads Rails for running tests, you may have to set it to true. 14 | config.eager_load = false 15 | 16 | # Configure static asset server for tests with Cache-Control for performance. 17 | config.serve_static_assets = true 18 | # config.static_cache_control = 'public, max-age=3600' 19 | 20 | # Show full error reports and disable caching. 21 | config.consider_all_requests_local = true 22 | config.action_controller.perform_caching = false 23 | 24 | # Raise exceptions instead of rendering exception templates. 25 | config.action_dispatch.show_exceptions = false 26 | 27 | # Disable request forgery protection in test environment. 28 | config.action_controller.allow_forgery_protection = false 29 | 30 | # Tell Action Mailer not to deliver emails to the real world. 31 | # The :test delivery method accumulates sent emails in the 32 | # ActionMailer::Base.deliveries array. 33 | config.action_mailer.delivery_method = :test 34 | 35 | # Print deprecation notices to the stderr. 36 | config.active_support.deprecation = :stderr 37 | 38 | # Raises error for missing translations 39 | # config.action_view.raise_on_missing_translations = true 40 | end 41 | -------------------------------------------------------------------------------- /spec/rails_app/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.action_dispatch.cookies_serializer = :json -------------------------------------------------------------------------------- /spec/rails_app/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /spec/rails_app/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | Dummy::Application.config.secret_key_base = 'existing secret token' 2 | Dummy::Application.config.secret_key_base = 'new secret key base' -------------------------------------------------------------------------------- /spec/rails_app/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_dummy_session' 4 | -------------------------------------------------------------------------------- /spec/rails_app/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /spec/rails_app/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | get "/users/:user_id/render_elsewhere(.:format)", :to => "likes#render_elsewhere" 3 | get "/users/:user_id/send_instructions", :to => "users#send_instructions" 4 | get "/users/noaction", :to => "users#noaction" 5 | get "/users/export/:id", :to => "users#export" 6 | resources :users do 7 | resources :likes 8 | end 9 | get "/home(.:format)", :to => "home#index", :as => :home 10 | get "/home/only_html", :to => "home#only_html", :as => :only_html 11 | get "/another(.:format)", :to => "home#another", :as => :another 12 | get "/useheader(.:format)", :to => "home#useheader", :as => :useheader 13 | get "/withpartial(.:format)", :to => "home#withpartial", :as => :withpartial 14 | get "/home/render_elsewhere(.:format)", :to => "home#render_elsewhere" 15 | get "/render_elsewhere(.:format)", :to => "home#render_elsewhere" 16 | root to: "home#index" 17 | end 18 | -------------------------------------------------------------------------------- /spec/rails_app/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: a379dda69862a8411c21a5657a822201520044ba6afc4eb650247079c545c6c566fa4119b818744c36d7faca4533542695e382a787ef9899a52754b4dcc4145c 15 | 16 | test: 17 | secret_key_base: be4cce38d09d5ef8d251576c17b633e28d36efd34843b2a0930bc9450e7bfc1dbad6600e2a0f1f901b4f26c43dd916732966d1428c1f8eeb1218765856e5d84a 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /spec/rails_app/db/migrate/20120717192452_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration 2 | def change 3 | create_table :users do |t| 4 | t.string :name 5 | t.string :last_name 6 | t.string :address 7 | t.string :email 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/rails_app/db/migrate/20121206210955_create_likes.rb: -------------------------------------------------------------------------------- 1 | class CreateLikes < ActiveRecord::Migration 2 | def change 3 | create_table :likes do |t| 4 | t.string :name 5 | t.integer :user_id 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/rails_app/db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # Note that this schema.rb definition is the authoritative source for your 6 | # database schema. If you need to create the application database on another 7 | # system, you should be using db:schema:load, not running all the migrations 8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 9 | # you'll amass, the slower it'll run and the greater likelihood for issues). 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema.define(version: 20121206210955) do 14 | 15 | create_table "likes", force: :cascade do |t| 16 | t.string "name" 17 | t.integer "user_id" 18 | t.datetime "created_at" 19 | t.datetime "updated_at" 20 | end 21 | 22 | create_table "users", force: :cascade do |t| 23 | t.string "name" 24 | t.string "last_name" 25 | t.string "address" 26 | t.string "email" 27 | t.datetime "created_at" 28 | t.datetime "updated_at" 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /spec/rails_app/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caxlsx/caxlsx_rails/0d6158f3663e671ee184913e66355222ade2a81c/spec/rails_app/log/.keep -------------------------------------------------------------------------------- /spec/rails_app/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /spec/rails_app/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /spec/rails_app/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /spec/rails_app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caxlsx/caxlsx_rails/0d6158f3663e671ee184913e66355222ade2a81c/spec/rails_app/public/favicon.ico -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] ||= "test" 2 | 3 | # Set up bundle to use gems 4 | require 'bundler/setup' 5 | Bundler.setup 6 | 7 | # Require Rails 8 | require 'rails' 9 | 10 | # Require the test app's environment 11 | require 'rails_app/config/environment' 12 | 13 | # Set up test gems 14 | require 'rspec/rails' 15 | require 'capybara/rspec' 16 | require 'roo' 17 | require 'byebug' 18 | 19 | ActiveRecord::Migration.maintain_test_schema! 20 | 21 | Dir[Rails.root.join("../../spec/support/**/*.rb")].each {|f| require f} 22 | 23 | RSpec.configure do |config| 24 | config.color = true 25 | config.formatter = 'documentation' 26 | config.use_transactional_fixtures = false 27 | config.infer_base_class_for_anonymous_controllers = false 28 | config.order = "random" 29 | end 30 | 31 | # TODO: move to the support folder 32 | module ::RSpec::Core 33 | class ExampleGroup 34 | include Capybara::DSL 35 | include Capybara::RSpecMatchers 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/support/mime_type_helper.rb: -------------------------------------------------------------------------------- 1 | def mime_type 2 | Rails.version.to_f >= 5 ? Mime[:xlsx] : Mime::XLSX 3 | end 4 | --------------------------------------------------------------------------------