activeadmin-xls 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.bundle/config +1 -0
- data/.editorconfig +9 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.yardops +1 -0
- data/CHANGELOG.md +20 -0
- data/Gemfile +30 -0
- data/LICENSE +22 -0
- data/README.md +131 -0
- data/Rakefile +23 -0
- data/activeadmin-xls.gemspec +27 -0
- data/lib/active_admin/xls/builder.rb +259 -0
- data/lib/active_admin/xls/dsl.rb +26 -0
- data/lib/active_admin/xls/engine.rb +20 -0
- data/lib/active_admin/xls/resource_controller_extension.rb +57 -0
- data/lib/active_admin/xls/resource_extension.rb +13 -0
- data/lib/active_admin/xls/version.rb +5 -0
- data/lib/activeadmin-xls.rb +9 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/rails_template.rb +73 -0
- data/spec/support/rails_template_with_data.rb +59 -0
- data/spec/support/templates/admin/stores.rb +1 -0
- data/spec/support/templates/cucumber.rb +24 -0
- data/spec/support/templates/cucumber_with_reloading.rb +5 -0
- data/spec/support/templates/en.yml +15 -0
- data/spec/xls/unit/build_download_format_links_spec.rb +48 -0
- data/spec/xls/unit/builder_spec.rb +195 -0
- data/spec/xls/unit/dsl_spec.rb +52 -0
- data/spec/xls/unit/resource_controller_spec.rb +44 -0
- data/spec/xls/unit/resource_spec.rb +26 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5542c9ca3fb9ec53761a8f17c84d33590ac41fd4
|
4
|
+
data.tar.gz: 262f8f4e6e8068e1f8e2fb41744c1695454a965c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0d13b40efc0caab8e86510fbec44a8d2c9f9eb196440a311a8a2d8113218782f2311d0afe23700ab1ca394a19f647c87c944f25da3e67e4123011b9fbec4b5a2
|
7
|
+
data.tar.gz: 6b80baec72b523eda62d72975e3158026c76f37a3e0d1ad149264ce4331fa6a583752fa5d63679354c14812b1669b471d0066f2925ad1778e5d212b7295b90f8
|
data/.bundle/config
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--- {}
|
data/.editorconfig
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
data/.yardops
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--no-private --protected app/**/*.rb - README.md LEGAL
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## 1.0.2
|
4
|
+
|
5
|
+
### Bug Fixes
|
6
|
+
|
7
|
+
* Fixes undefined local variable or `method max_per_page` [#3][] by [@rewritten][]
|
8
|
+
|
9
|
+
## 1.0.3
|
10
|
+
|
11
|
+
### Updates
|
12
|
+
|
13
|
+
* Move require rake from gemspec to lib/activeadmin-xls.rb [#4][] by [@ejaypcanaria][]
|
14
|
+
|
15
|
+
<!--- Link List --->
|
16
|
+
[#3]: https://github.com/thambley/activeadmin-xls/issues/3
|
17
|
+
[#4]: https://github.com/thambley/activeadmin-xls/pull/4
|
18
|
+
|
19
|
+
[@rewritten]: https://github.com/rewritten
|
20
|
+
[@ejaypcanaria]: https://github.com/ejaypcanaria
|
data/Gemfile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'activeadmin', '~> 1.0'
|
4
|
+
gem 'spreadsheet', '~> 1.1', '>= 1.1.4'
|
5
|
+
|
6
|
+
group :development, :test do
|
7
|
+
gem 'haml', require: false
|
8
|
+
gem 'rails-i18n' # Gives us default i18n for many languages
|
9
|
+
gem 'rdiscount' # For yard
|
10
|
+
gem 'sprockets'
|
11
|
+
gem 'sqlite3'
|
12
|
+
gem 'yard'
|
13
|
+
end
|
14
|
+
|
15
|
+
group :test do
|
16
|
+
gem 'capybara'
|
17
|
+
gem 'cucumber-rails', require: false
|
18
|
+
gem 'database_cleaner'
|
19
|
+
gem 'guard-coffeescript'
|
20
|
+
gem 'guard-rspec'
|
21
|
+
gem 'inherited_resources'
|
22
|
+
gem 'jasmine'
|
23
|
+
gem 'jslint_on_rails', '~> 1.0.6'
|
24
|
+
gem 'launchy'
|
25
|
+
gem 'rspec-mocks'
|
26
|
+
gem 'rspec-rails'
|
27
|
+
gem 'sass-rails'
|
28
|
+
gem 'shoulda-matchers', '1.0.0'
|
29
|
+
gem 'simplecov', require: false
|
30
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Todd Hambley
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
# Active Admin Xls: Excel Spreadsheet Export for Active Admin
|
2
|
+
|
3
|
+
**Git**: [http://github.com/thambley/activeadmin-xls](http://github.com/thambley/activeadmin-xls)
|
4
|
+
|
5
|
+
**Author**: Todd Hambley
|
6
|
+
|
7
|
+
**Copyright**: 2014 ~ 2017
|
8
|
+
|
9
|
+
**License**: MIT License
|
10
|
+
|
11
|
+
**Latest Version**: 1.0.4
|
12
|
+
|
13
|
+
**Release Date**: 2017.11.22
|
14
|
+
|
15
|
+
## Synopsis
|
16
|
+
|
17
|
+
This gem provides xls downloads for Active Admin resources.
|
18
|
+
|
19
|
+
This gem borrows heavily from [https://github.com/randym/activeadmin-axlsx](https://github.com/randym/activeadmin-axlsx) and [https://github.com/splendeo/to_xls](https://github.com/splendeo/to_xls).
|
20
|
+
|
21
|
+
Usage example:
|
22
|
+
|
23
|
+
Add the following to your Gemfile and you are good to go.
|
24
|
+
All resource index views will now include a link for download directly
|
25
|
+
to xls.
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
gem 'activeadmin-xls'
|
29
|
+
```
|
30
|
+
|
31
|
+
## Cool Toys
|
32
|
+
|
33
|
+
Here are a few quick examples of things you can easily tweak.
|
34
|
+
|
35
|
+
### Localize column headers
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
# app/admin/posts.rb
|
39
|
+
ActiveAdmin.register Post do
|
40
|
+
config.xls_builder.i18n_scope = [:active_record, :models, :posts]
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
### Use blocks for adding computed fields
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
# app/admin/posts.rb
|
48
|
+
ActiveAdmin.register Post do
|
49
|
+
config.xls_builder.column('author_name') do |resource|
|
50
|
+
resource.author.name
|
51
|
+
end
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
### Change the column header format
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# app/admin/posts.rb
|
59
|
+
ActiveAdmin.register Post do
|
60
|
+
config.xls_builder.header_format = { weight: :bold,
|
61
|
+
color: :blue }
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
### Remove columns
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
# app/admin/posts.rb
|
69
|
+
ActiveAdmin.register Post do
|
70
|
+
config.xls_builder.delete_columns :id, :created_at, :updated_at
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
## Using the DSL
|
75
|
+
|
76
|
+
Everything that you do with the config's default builder can be done via
|
77
|
+
the resource DSL.
|
78
|
+
|
79
|
+
Below is an example of the DSL
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
ActiveAdmin.register Post do
|
83
|
+
|
84
|
+
# i18n_scope and header style are set via options
|
85
|
+
xls(i18n_scope: [:active_admin, :xls, :post],
|
86
|
+
header_format: { weight: :bold, color: :blue }) do
|
87
|
+
|
88
|
+
# Specify that you want to white list column output.
|
89
|
+
# whitelist
|
90
|
+
|
91
|
+
# Do not serialize the header, only output data.
|
92
|
+
# skip_header
|
93
|
+
|
94
|
+
# deleting columns from the report
|
95
|
+
delete_columns :id, :created_at, :updated_at
|
96
|
+
|
97
|
+
# adding a column to the report
|
98
|
+
column(:author) { |post| "#{post.author.first_name} #{post.author.last_name}" }
|
99
|
+
|
100
|
+
# inserting additional data with after_filter
|
101
|
+
after_filter do |sheet|
|
102
|
+
# todo
|
103
|
+
end
|
104
|
+
|
105
|
+
# inserting data with before_filter
|
106
|
+
before_filter do |sheet|
|
107
|
+
# todo
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
## Specs
|
114
|
+
|
115
|
+
Running specs for this gem requires that you construct a rails application.
|
116
|
+
To execute the specs, navigate to the gem directory,
|
117
|
+
run bundle install and run these to rake tasks:
|
118
|
+
|
119
|
+
```text
|
120
|
+
bundle exec rake setup
|
121
|
+
```
|
122
|
+
|
123
|
+
```text
|
124
|
+
bundle exec rake
|
125
|
+
```
|
126
|
+
|
127
|
+
## Copyright and License
|
128
|
+
|
129
|
+
activeadmin-xls © 2014 by [Todd Hambley](mailto:thambley@travelleaders.com).
|
130
|
+
|
131
|
+
activeadmin-xls is licensed under the MIT license. Please see the LICENSE document for more information.
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require "activeadmin"
|
3
|
+
require "rspec/core/rake_task"
|
4
|
+
|
5
|
+
desc "Creates a test rails app for the specs to run against"
|
6
|
+
task :setup do
|
7
|
+
require 'rails/version'
|
8
|
+
system("mkdir spec/rails") unless File.exists?("spec/rails")
|
9
|
+
system "bundle exec rails new spec/rails/rails-#{Rails::VERSION::STRING} -m spec/support/rails_template_with_data.rb"
|
10
|
+
end
|
11
|
+
|
12
|
+
RSpec::Core::RakeTask.new
|
13
|
+
task :default => :spec
|
14
|
+
task :test => :spec
|
15
|
+
|
16
|
+
desc "build the gem"
|
17
|
+
task :build do
|
18
|
+
system "gem build activeadmin-xls.gemspec"
|
19
|
+
end
|
20
|
+
desc "build and release the gem"
|
21
|
+
task :release => :build do
|
22
|
+
system "gem push activeadmin-xls-#{ActiveAdmin::Xls::VERSION}.gem"
|
23
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.expand_path('../lib/active_admin/xls/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'activeadmin-xls'
|
5
|
+
s.version = ActiveAdmin::Xls::VERSION
|
6
|
+
s.author = 'Todd Hambley'
|
7
|
+
s.email = 'thambley@travelleaders.com'
|
8
|
+
s.homepage = 'https://github.com/thambley/activeadmin-xls'
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
11
|
+
s.license = 'MIT'
|
12
|
+
s.summary = <<-SUMMARY
|
13
|
+
Adds excel (xls) downloads for resources within the Active Admin framework.
|
14
|
+
SUMMARY
|
15
|
+
s.description = <<-DESC
|
16
|
+
This gem provides excel/xls downloads for resources in Active Admin.
|
17
|
+
DESC
|
18
|
+
s.files = `git ls-files`.split("\n").sort
|
19
|
+
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
20
|
+
s.test_files = Dir.glob('{spec/**/*}')
|
21
|
+
|
22
|
+
s.add_runtime_dependency 'activeadmin', '>= 0.6.6', '< 2'
|
23
|
+
s.add_runtime_dependency 'spreadsheet', '~> 1.0'
|
24
|
+
|
25
|
+
s.required_ruby_version = '>= 1.9.2'
|
26
|
+
s.require_path = 'lib'
|
27
|
+
end
|
@@ -0,0 +1,259 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'spreadsheet'
|
3
|
+
|
4
|
+
module ActiveAdmin
|
5
|
+
module Xls
|
6
|
+
# Builder for xls data.
|
7
|
+
class Builder
|
8
|
+
include MethodOrProcHelper
|
9
|
+
|
10
|
+
# @param resource_class The resource this builder generate column
|
11
|
+
# information for.
|
12
|
+
# @param [Hash] options the options for this builder
|
13
|
+
# @option [Hash] :header_format - a hash of format properties to apply
|
14
|
+
# to the header row. Any properties specified will be merged with the
|
15
|
+
# default header styles. @see https://github.com/zdavatz/spreadsheet/blob/master/lib/spreadsheet/format.rb
|
16
|
+
# @option [Array] :i18n_scope - the I18n scope to use when looking
|
17
|
+
# up localized column headers.
|
18
|
+
# @param [Block] Any block given will evaluated against this instance of
|
19
|
+
# Builder. That means you can call any method on the builder from within
|
20
|
+
# that block.
|
21
|
+
# @example
|
22
|
+
# ActiveAdmin::Xls:Builder.new(Post, i18n: [:xls]) do
|
23
|
+
# delete_columns :id, :created_at, :updated_at
|
24
|
+
# column(:author_name) { |post| post.author.name }
|
25
|
+
# after_filter { |sheet|
|
26
|
+
#
|
27
|
+
# }
|
28
|
+
# end
|
29
|
+
# @see ActiveAdmin::Axlsx::DSL
|
30
|
+
def initialize(resource_class, options = {}, &block)
|
31
|
+
@skip_header = false
|
32
|
+
@columns = resource_columns(resource_class)
|
33
|
+
parse_options options
|
34
|
+
instance_eval(&block) if block_given?
|
35
|
+
end
|
36
|
+
|
37
|
+
# The default header style
|
38
|
+
# @return [Hash]
|
39
|
+
def header_format
|
40
|
+
@header_format ||= {}
|
41
|
+
end
|
42
|
+
|
43
|
+
alias header_style header_format
|
44
|
+
|
45
|
+
# This has can be used to override the default header style for your
|
46
|
+
# sheet. Any values you provide will be merged with the default styles.
|
47
|
+
# Precidence is given to your hash
|
48
|
+
# @see https://github.com/zdavatz/spreadsheet/blob/master/lib/spreadsheet/format.rb
|
49
|
+
# for more details on how to create and apply style.
|
50
|
+
def header_format=(format_hash)
|
51
|
+
@header_format = header_format.merge(format_hash)
|
52
|
+
end
|
53
|
+
|
54
|
+
alias header_style= header_format=
|
55
|
+
|
56
|
+
# Indicates that we do not want to serialize the column headers
|
57
|
+
def skip_header
|
58
|
+
@skip_header = true
|
59
|
+
end
|
60
|
+
|
61
|
+
# The scope to use when looking up column names to generate the
|
62
|
+
# report header
|
63
|
+
def i18n_scope
|
64
|
+
@i18n_scope ||= nil
|
65
|
+
end
|
66
|
+
|
67
|
+
# This is the I18n scope that will be used when looking up your
|
68
|
+
# colum names in the current I18n locale.
|
69
|
+
# If you set it to [:active_admin, :resources, :posts] the
|
70
|
+
# serializer will render the value at active_admin.resources.posts.title
|
71
|
+
# in the current translations
|
72
|
+
# @note If you do not set this, the column name will be titleized.
|
73
|
+
attr_writer :i18n_scope
|
74
|
+
|
75
|
+
# The stored block that will be executed after your report is generated.
|
76
|
+
def after_filter(&block)
|
77
|
+
@after_filter = block
|
78
|
+
end
|
79
|
+
|
80
|
+
# the stored block that will be executed before your report is generated.
|
81
|
+
def before_filter(&block)
|
82
|
+
@before_filter = block
|
83
|
+
end
|
84
|
+
|
85
|
+
# The columns this builder will be serializing
|
86
|
+
attr_reader :columns
|
87
|
+
|
88
|
+
# The collection we are serializing.
|
89
|
+
# @note This is only available after serialize has been called,
|
90
|
+
# and is reset on each subsequent call.
|
91
|
+
attr_reader :collection
|
92
|
+
|
93
|
+
# removes all columns from the builder. This is useful when you want to
|
94
|
+
# only render specific columns. To remove specific columns use
|
95
|
+
# ignore_column.
|
96
|
+
def clear_columns
|
97
|
+
@columns = []
|
98
|
+
end
|
99
|
+
|
100
|
+
# Clears the default columns array so you can whitelist only the columns
|
101
|
+
# you want to export
|
102
|
+
def whitelist
|
103
|
+
@columns = []
|
104
|
+
end
|
105
|
+
|
106
|
+
# Add a column
|
107
|
+
# @param [Symbol] name The name of the column.
|
108
|
+
# @param [Proc] block A block of code that is executed on the resource
|
109
|
+
# when generating row data for this column.
|
110
|
+
def column(name, &block)
|
111
|
+
@columns << Column.new(name, block)
|
112
|
+
end
|
113
|
+
|
114
|
+
# removes columns by name
|
115
|
+
# each column_name should be a symbol
|
116
|
+
def delete_columns(*column_names)
|
117
|
+
@columns.delete_if { |column| column_names.include?(column.name) }
|
118
|
+
end
|
119
|
+
|
120
|
+
# Serializes the collection provided
|
121
|
+
# @return [Spreadsheet::Workbook]
|
122
|
+
def serialize(collection, view_context)
|
123
|
+
@collection = collection
|
124
|
+
@view_context = view_context
|
125
|
+
apply_filter @before_filter
|
126
|
+
export_collection(collection)
|
127
|
+
apply_filter @after_filter
|
128
|
+
to_stream
|
129
|
+
end
|
130
|
+
|
131
|
+
# Xls column
|
132
|
+
class Column
|
133
|
+
def initialize(name, block = nil)
|
134
|
+
@name = name
|
135
|
+
@data = block || @name
|
136
|
+
end
|
137
|
+
|
138
|
+
attr_reader :name, :data
|
139
|
+
|
140
|
+
def localized_name(i18n_scope = nil)
|
141
|
+
return name.to_s.titleize unless i18n_scope
|
142
|
+
I18n.t name, scope: i18n_scope
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def to_stream
|
149
|
+
stream = StringIO.new('')
|
150
|
+
book.write stream
|
151
|
+
clean_up
|
152
|
+
stream.string
|
153
|
+
end
|
154
|
+
|
155
|
+
def clean_up
|
156
|
+
@book = @sheet = nil
|
157
|
+
end
|
158
|
+
|
159
|
+
def export_collection(collection)
|
160
|
+
return if columns.none?
|
161
|
+
row_index = 0
|
162
|
+
|
163
|
+
unless @skip_header
|
164
|
+
header_row(collection)
|
165
|
+
row_index = 1
|
166
|
+
end
|
167
|
+
|
168
|
+
collection.each do |resource|
|
169
|
+
fill_row(sheet.row(row_index), resource_data(resource))
|
170
|
+
row_index += 1
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# tranform column names into array of localized strings
|
175
|
+
# @return [Array]
|
176
|
+
def header_row(collection)
|
177
|
+
row = sheet.row(0)
|
178
|
+
apply_format_to_row(row, create_format(header_format))
|
179
|
+
fill_row(row, header_data_for(collection))
|
180
|
+
end
|
181
|
+
|
182
|
+
def header_data_for(collection)
|
183
|
+
resource = collection.first
|
184
|
+
columns.map do |column|
|
185
|
+
column.localized_name(i18n_scope) if in_scope(resource, column)
|
186
|
+
end.compact
|
187
|
+
end
|
188
|
+
|
189
|
+
def apply_filter(filter)
|
190
|
+
filter.call(sheet) if filter
|
191
|
+
end
|
192
|
+
|
193
|
+
def parse_options(options)
|
194
|
+
options.each do |key, value|
|
195
|
+
send("#{key}=", value) if respond_to?("#{key}=") && !value.nil?
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def resource_data(resource)
|
200
|
+
columns.map do |column|
|
201
|
+
call_method_or_proc_on resource, column.data if in_scope(resource,
|
202
|
+
column)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def in_scope(resource, column)
|
207
|
+
return true unless column.name.is_a?(Symbol)
|
208
|
+
resource.respond_to?(column.name)
|
209
|
+
end
|
210
|
+
|
211
|
+
def sheet
|
212
|
+
@sheet ||= book.create_worksheet
|
213
|
+
end
|
214
|
+
|
215
|
+
def book
|
216
|
+
@book ||= ::Spreadsheet::Workbook.new
|
217
|
+
end
|
218
|
+
|
219
|
+
def resource_columns(resource)
|
220
|
+
[Column.new(:id)] + resource.content_columns.map do |column|
|
221
|
+
Column.new(column.name.to_sym)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def create_format(format_hash)
|
226
|
+
Spreadsheet::Format.new format_hash
|
227
|
+
end
|
228
|
+
|
229
|
+
def apply_format_to_row(row, format)
|
230
|
+
row.default_format = format if format
|
231
|
+
end
|
232
|
+
|
233
|
+
def fill_row(row, column)
|
234
|
+
case column
|
235
|
+
when Hash
|
236
|
+
column.each_value { |values| fill_row(row, values) }
|
237
|
+
when Array
|
238
|
+
column.each { |value| fill_row(row, value) }
|
239
|
+
else
|
240
|
+
# raise ArgumentError,
|
241
|
+
# "column #{column} has an invalid class (#{ column.class })"
|
242
|
+
row.push(column)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def method_missing(method_name, *arguments)
|
247
|
+
if @view_context.respond_to? method_name
|
248
|
+
@view_context.send method_name, *arguments
|
249
|
+
else
|
250
|
+
super
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def respond_to_missing?(method_name, include_private = false)
|
255
|
+
@view_context.respond_to?(method_name) || super
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
module Xls
|
3
|
+
# extends activeadmin dsl to include xls
|
4
|
+
module DSL
|
5
|
+
delegate(:after_filter,
|
6
|
+
:before_filter,
|
7
|
+
:column,
|
8
|
+
:delete_columns,
|
9
|
+
:header_format,
|
10
|
+
:header_style,
|
11
|
+
:i18n_scope,
|
12
|
+
:skip_header,
|
13
|
+
:whitelist,
|
14
|
+
to: :xls_builder,
|
15
|
+
prefix: :config)
|
16
|
+
|
17
|
+
def xls(options = {}, &block)
|
18
|
+
config.xls_builder = ActiveAdmin::Xls::Builder.new(
|
19
|
+
config.resource_class,
|
20
|
+
options,
|
21
|
+
&block
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
module Xls
|
3
|
+
# extends activeadmin with xls downloads
|
4
|
+
class Engine < ::Rails::Engine
|
5
|
+
engine_name 'active_admin_xls'
|
6
|
+
|
7
|
+
initializer 'active_admin.xls', group: :all do
|
8
|
+
if Mime::Type.lookup_by_extension(:xls).nil?
|
9
|
+
Mime::Type.register 'application/vnd.ms-excel', :xls
|
10
|
+
end
|
11
|
+
|
12
|
+
ActiveAdmin::Views::PaginatedCollection.add_format :xls
|
13
|
+
|
14
|
+
ActiveAdmin::ResourceDSL.send :include, ActiveAdmin::Xls::DSL
|
15
|
+
ActiveAdmin::Resource.send :include, ActiveAdmin::Xls::ResourceExtension
|
16
|
+
ActiveAdmin::ResourceController.send :include, ActiveAdmin::Xls::ResourceControllerExtension
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ActiveAdmin
|
2
|
+
module Xls
|
3
|
+
module ResourceControllerExtension
|
4
|
+
def self.included(base)
|
5
|
+
base.send :alias_method_chain, :per_page, :xls
|
6
|
+
base.send :alias_method_chain, :index, :xls
|
7
|
+
base.send :alias_method_chain, :rescue_active_admin_access_denied, :xls
|
8
|
+
base.send :respond_to, :xls
|
9
|
+
end
|
10
|
+
|
11
|
+
def index_with_xls
|
12
|
+
index_without_xls do |format|
|
13
|
+
yield format if block_given?
|
14
|
+
|
15
|
+
format.xls do
|
16
|
+
xls = active_admin_config.xls_builder.serialize(collection,
|
17
|
+
view_context)
|
18
|
+
send_data(xls,
|
19
|
+
filename: xls_filename,
|
20
|
+
type: Mime::Type.lookup_by_extension(:xls))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def rescue_active_admin_access_denied_with_xls(exception)
|
26
|
+
if request.format == Mime::Type.lookup_by_extension(:xls)
|
27
|
+
respond_to do |format|
|
28
|
+
format.xls do
|
29
|
+
flash[:error] = "#{exception.message} Review download_links in initializers/active_admin.rb"
|
30
|
+
redirect_backwards_or_to_root
|
31
|
+
end
|
32
|
+
end
|
33
|
+
else
|
34
|
+
rescue_active_admin_access_denied_without_xls(exception)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# patch per_page to use the CSV record max for pagination
|
39
|
+
# when the format is xls
|
40
|
+
def per_page_with_xls
|
41
|
+
if request.format == Mime::Type.lookup_by_extension(:xls)
|
42
|
+
return max_per_page if respond_to?(:max_per_page, true)
|
43
|
+
active_admin_config.max_per_page
|
44
|
+
end
|
45
|
+
|
46
|
+
per_page_without_xls
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns a filename for the xls file using the collection_name
|
50
|
+
# and current date such as 'my-articles-2011-06-24.xls'.
|
51
|
+
def xls_filename
|
52
|
+
timestamp = Time.now.strftime('%Y-%m-%d')
|
53
|
+
"#{resource_collection_name.to_s.tr('_', '-')}-#{timestamp}.xls"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'active_admin'
|
3
|
+
|
4
|
+
require 'active_admin/xls/version'
|
5
|
+
require 'active_admin/xls/builder'
|
6
|
+
require 'active_admin/xls/dsl'
|
7
|
+
require 'active_admin/xls/resource_extension'
|
8
|
+
require 'active_admin/xls/resource_controller_extension'
|
9
|
+
require 'active_admin/xls/engine'
|