active_admin-exportable 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 87e5645f5817a953c4cbc2ab61cc5f6de965981c695f7a196b19b2d2b37c8e96
4
+ data.tar.gz: 40010fe028c4815e8b74e5839df7497ac81e4c56e4b85e2ceb9d42de57a965ea
5
+ SHA512:
6
+ metadata.gz: 4b95c94889333ce39ce407d46f4b00e7eadab3b03482126864a27f17f2902eda2a32c965137e343d7ca5a21347a21147b0a4ae02582c62d4daa6b471fe21cfb3
7
+ data.tar.gz: 60bbcaedf2a77a2dcb5929766e9f98e7299c26c974580769cc4d65e9baeefc96dff2d3fa72f12f58112991eb1106d74309736b530dd8255eb28ef2a223ba1cca
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .rspec
2
+ .bundle/
3
+ log/*.log
4
+ pkg/
5
+ Gemfile.lock
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ # Change Log
2
+
3
+ ## 0.1.0 - 2021-05-21
4
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in activeadmin-subnav.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) Wagner Caixeta
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # ActiveAdmin::Exportable
2
+
3
+ Allow user to export/import of ActiveRecord records and associated records in ActiveAdmin.
4
+
5
+ # Usage
6
+
7
+ Add "exportable" to
8
+
9
+ ```ruby
10
+ ActiveAdmin.register Blog do
11
+ exportable includes: [:posts], format: :json, remove_ids: true, filename_method: :my_custom_filename_method
12
+ end
13
+ ```
14
+ # Options
15
+
16
+ ## includes
17
+ Default: []
18
+
19
+ Use the same syntax of ActiveRecord includes.
20
+
21
+ ## format
22
+ Default: 'json'
23
+
24
+ Export will accept anything "to_format", like json and yaml, but import will only accept 'json' and 'yaml'.
25
+
26
+ ## remove_ids
27
+ Default: true
28
+
29
+ The export will remove ids and association ids to avoid conflict on import in another system.
30
+ The import process can restore associations creating new ids.
31
+
32
+ ## filename_method
33
+ If you dont define this the name os files will be "#{the_resource_class_name}_#{id}"
34
+
35
+ # Installation
36
+
37
+ Add this line to your application's Gemfile:
38
+
39
+ ```ruby
40
+ gem 'active_admin-exportable', '~> 0.1.0'
41
+ ```
42
+
43
+ And then execute:
44
+
45
+ $ bundle
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'active_admin/exportable/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'active_admin-exportable'
9
+ spec.version = ActiveAdmin::Exportable::VERSION
10
+ spec.authors = ['Wagner Caixeta']
11
+ spec.email = ['wagner.caixeta@gmail.com.com']
12
+ spec.summary = 'A export/import tool for ActiveAdmin.'
13
+ spec.description = 'Allow user to export/import of ActiveRecord records and associated records in ActiveAdmin.'
14
+ spec.homepage = 'https://github.com/zorab47/active_admin-exportable'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'activeadmin'
23
+
24
+ spec.add_development_dependency 'activerecord'
25
+ spec.add_development_dependency 'bundler'
26
+ spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'rspec'
28
+ # required for active admin
29
+ spec.add_development_dependency 'sass-rails'
30
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveAdmin.register_page 'Import' do
4
+ menu parent: 'Exportable'
5
+ controller do
6
+ private
7
+
8
+ def import_options
9
+ allow_update = ActiveModel::Type::Boolean.new.cast(params[:import][:allow_update])
10
+ file_path = params[:import][:file]&.path
11
+ format = params[:import][:format]
12
+ raise 'Format is required.' if format.blank?
13
+ raise 'File is required.' if file_path.blank?
14
+
15
+ { path: file_path, format: format, allow_update: allow_update }
16
+ end
17
+ end
18
+
19
+ content do
20
+ columns do
21
+ column do
22
+ div do
23
+ active_admin_form_for 'import', url: 'import/upload' do |f|
24
+ f.inputs name: 'Import', class: 'inputs' do
25
+ f.input :format, collection: %i[json yaml], input_html: { value: 'json' }
26
+ f.input :allow_update, as: :boolean
27
+ f.input :file, as: :file
28
+ f.action :submit
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ page_action :upload, method: :post do
37
+ imported = ActiveAdmin::Exportable::Importer.new(**import_options)
38
+ imported.import
39
+ redirect_to admin_import_path, notice: 'Imported'
40
+ rescue StandardError => e
41
+ redirect_to admin_import_path, flash: { error: e.message }
42
+ end
43
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_admin'
4
+ require 'active_admin/exportable/version'
5
+ require 'active_admin/exportable/engine'
6
+ require 'active_admin/exportable/exporter'
7
+ require 'active_admin/exportable/importer'
8
+
9
+ module ActiveAdmin
10
+ module Exportable
11
+ extend ActiveSupport::Concern
12
+
13
+ def exportable(options = {})
14
+ includes = options.fetch(:includes) { [] }
15
+ remove_ids = options.fetch(:remove_ids, true)
16
+ filename_method = options[:filename_method]
17
+ format = options.fetch(:format, :json)
18
+ enable_resource_exportion(includes: includes, remove_ids: remove_ids, filename_method: filename_method,
19
+ format: format)
20
+ end
21
+
22
+ private
23
+
24
+ def enable_resource_exportion(includes:, remove_ids:, filename_method:, format:)
25
+ action_item(*compatible_action_item_parameters) do
26
+ if controller.action_methods.include?('new') && authorized?(ActiveAdmin::Auth::CREATE,
27
+ active_admin_config.resource_class)
28
+ link_to(
29
+ I18n.t(
30
+ :export_model,
31
+ default: 'Export %{model}',
32
+ scope: [:active_admin],
33
+ model: active_admin_config.resource_label
34
+ ),
35
+ { action: :export }
36
+ )
37
+ end
38
+ end
39
+
40
+ member_action :export do
41
+ resource = resource_class.find(params[:id])
42
+
43
+ authorize! ActiveAdmin::Auth::CREATE, resource
44
+
45
+ exported = ActiveAdmin::Exportable::Exporter.new(resource, includes: includes,
46
+ remove_ids: remove_ids).export.send("to_#{format}")
47
+ filename = "#{resource.send(filename_method)}.#{format}" if filename_method.present?
48
+ filename ||= "#{resource_class.name.downcase}_#{resource.id}.#{format}"
49
+
50
+ send_data exported, type: "application/#{format}", filename: filename
51
+ end
52
+ end
53
+
54
+ # For ActiveAdmin `action_item` compatibility.
55
+ #
56
+ # - When ActiveAdmin is less than 1.0.0.pre1 exclude name parameter from
57
+ # calls to `action_item` for compatibility.
58
+ # - When 1.0.0.pre1 or greater provide name to `action_item` to avoid the
59
+ # warning message, and later an error.
60
+ #
61
+ # Returns Array of parameters.
62
+ def compatible_action_item_parameters
63
+ parameters = [{ only: %i[show edit] }]
64
+ parameters.unshift(:exportable_export) if action_item_name_required?
65
+ parameters
66
+ end
67
+
68
+ def action_item_name_required?
69
+ method(:action_item).parameters.count == 3
70
+ end
71
+ end
72
+ end
73
+
74
+ ActiveAdmin::ResourceDSL.include ActiveAdmin::Exportable
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdmin
4
+ module Exportable
5
+ class Engine < Rails::Engine
6
+ initializer 'active_admin' do |_app|
7
+ ActiveAdmin.before_load do |app|
8
+ app.load_paths << File.expand_path('../../../app/admin', __dir__)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdmin
4
+ module Exportable
5
+ class Exporter
6
+ # TODO: extract this to other gem.
7
+ def initialize(record, includes: [], remove_ids: false)
8
+ unless record.is_a?(ActiveRecord::Relation) || record.is_a?(ActiveRecord::Base)
9
+ raise ArgumentError, 'You need provide an ActiveRecord record as argument.'
10
+ end
11
+
12
+ @root = RootStruct.new(node: record, includes: includes, remove_ids: remove_ids)
13
+ end
14
+
15
+ def export
16
+ @root.data
17
+ end
18
+
19
+ def to_file(path:)
20
+ File.open(path, 'w') { |f| f.write to_json }
21
+ end
22
+
23
+ def to_json(*_args)
24
+ export.to_json
25
+ end
26
+
27
+ class RootStruct
28
+ def initialize(node:, remove_ids:, includes: [])
29
+ @node = node
30
+ @includes = includes
31
+ @remove_ids = remove_ids
32
+ end
33
+
34
+ def data
35
+ if @node.respond_to?(:size)
36
+ @node.map do |n|
37
+ generate_data(node: n, includes: @includes)
38
+ end
39
+ else
40
+ generate_data(node: @node, includes: @includes)
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def generate_data(node:, includes:)
47
+ attributes = node.attributes
48
+ a_data = associations_data(node: node, includes: includes)
49
+
50
+ if @remove_ids
51
+ attributes.delete('id')
52
+ a_data.map do |a|
53
+ [a[:foreign_type], a[:foreign_key]] if a[:kind] == 'belongs_to'
54
+ end.flatten.compact.each do |key|
55
+ attributes.delete(key)
56
+ end
57
+ end
58
+
59
+ {
60
+ class_name: node.class.name,
61
+ attributes: attributes,
62
+ associations: a_data
63
+ }
64
+ end
65
+
66
+ def associations_data(node:, includes:)
67
+ association_data = generate_association_data(node: node, includes: includes)
68
+ return [association_data.data] if association_data.instance_of?(AssociationStruct)
69
+
70
+ association_data.flatten.map(&:data)
71
+ end
72
+
73
+ def generate_association_data(node:, includes:)
74
+ return [] if includes.nil? || includes.empty?
75
+
76
+ case includes
77
+ when Hash
78
+ generate_association_data_for_hash(node: node, includes: includes)
79
+ when Array
80
+ generate_association_data_for_array(node: node, includes: includes)
81
+ when Symbol
82
+ generate_association_data_for_symbol(node: node, includes: includes)
83
+ end
84
+ end
85
+
86
+ def generate_association_data_for_hash(node:, includes:)
87
+ includes.map do |association_name, inner_includes|
88
+ AssociationStruct.new(record: node, association_name: association_name, remove_ids: @remove_ids,
89
+ next_level_includes: inner_includes)
90
+ end
91
+ end
92
+
93
+ def generate_association_data_for_array(node:, includes:)
94
+ includes.map do |association_name|
95
+ # It needs to "pass" again because we don't know the element's kinds.
96
+ generate_association_data(node: node, includes: association_name)
97
+ end
98
+ end
99
+
100
+ def generate_association_data_for_symbol(node:, includes:)
101
+ if node.respond_to?(:size)
102
+ node.map do |inner_node|
103
+ AssociationStruct.new(record: inner_node, association_name: includes, remove_ids: @remove_ids)
104
+ end
105
+ else
106
+ AssociationStruct.new(record: node, association_name: includes, remove_ids: @remove_ids)
107
+ end
108
+ end
109
+ end
110
+
111
+ class AssociationStruct
112
+ def initialize(record:, association_name:, remove_ids:, next_level_includes: nil)
113
+ @next_level_includes = next_level_includes
114
+ @reflection = record.association(association_name).reflection
115
+ @association = record.send(association_name)
116
+ @remove_ids = remove_ids
117
+ end
118
+
119
+ def data
120
+ {
121
+ name: @reflection.name,
122
+ inverse: @reflection.inverse_of&.name,
123
+ foreign_key: @reflection.foreign_key,
124
+ foreign_type: @reflection.foreign_type,
125
+ kind: @reflection.class.name.match(/.*::(?<shortname>\w+)Reflection/)['shortname'].underscore,
126
+ content: RootStruct.new(node: @association, includes: @next_level_includes, remove_ids: @remove_ids).data
127
+ }.compact
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdmin
4
+ module Exportable
5
+ class Importer
6
+ def initialize(path: nil, data: nil, json: nil, yaml: nil, allow_update: false, ignore_ids: false, format: nil)
7
+ @data = data if data.present?
8
+ @data ||= path_to_data(path, format: format) if path.present?
9
+ @data ||= json_to_data(json) if json.present?
10
+ @data ||= yaml_to_data(yaml) if yaml.present?
11
+ @allow_update = allow_update
12
+ @ignore_ids = ignore_ids
13
+ end
14
+
15
+ def import
16
+ ActiveRecord::Base.transaction do
17
+ process_associations_content(@data)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def path_to_data(path, format: nil)
24
+ format ||= path.match(/.(?<format>\w+)$/)[:format]
25
+ case format.to_s
26
+ when 'json'
27
+ json_to_data(File.open(path).read)
28
+ when 'yaml'
29
+ yaml_to_data(File.open(path).read)
30
+ end
31
+ end
32
+
33
+ def json_to_data(json)
34
+ JSON.parse(json)
35
+ end
36
+
37
+ def yaml_to_data(yaml)
38
+ YAML.safe_load(yaml)
39
+ end
40
+
41
+ def process_associations_content(content, relation: nil, relation_name: nil)
42
+ if content.is_a?(Array)
43
+ content.each do |c|
44
+ process_data(c.with_indifferent_access, relation: relation, relation_name: relation_name)
45
+ end
46
+ else
47
+ process_data(content.with_indifferent_access, relation: relation, relation_name: relation_name)
48
+ end
49
+ end
50
+
51
+ def process_data(data, relation: nil, relation_name: nil)
52
+ record = update_or_create_record_from_data(data)
53
+ assign_relation_if_needed(record, relation, relation_name)
54
+ create_and_assign_belongs_to_associations(record, data)
55
+ record.save!
56
+ create_non_belongs_to_associations(record, data)
57
+ record
58
+ rescue StandardError => e
59
+ raise "#{e.message} - details: #{record.inspect}"
60
+ end
61
+
62
+ def update_or_create_record_from_data(data)
63
+ record = find_or_initialize_from_data(data)
64
+ return record if !@allow_update && !record.new_record?
65
+
66
+ record.attributes = data[:attributes]
67
+ record
68
+ end
69
+
70
+ def find_or_initialize_from_data(data)
71
+ klass = data[:class_name].constantize
72
+ data[:attributes][:id] = nil if @ignore_ids
73
+ where_opts = if data[:attributes][:id].present?
74
+ { id: data[:attributes][:id] }
75
+ elsif klass.respond_to?(:exportable_search_attributes)
76
+ klass.exportable_search_attributes.to_h { |x| [x, data[:attributes][x]] }
77
+ end
78
+ record = klass.where(where_opts).take if where_opts.present?
79
+ record || klass.new
80
+ end
81
+
82
+ def assign_relation_if_needed(record, relation, relation_name)
83
+ record.send("#{relation_name}=", relation) if relation.present?
84
+ end
85
+
86
+ def create_and_assign_belongs_to_associations(record, data)
87
+ filter_belongs_to_associations(data).each do |association_data|
88
+ association_record = process_data(association_data[:content])
89
+ record.send("#{association_data[:name]}=", association_record)
90
+ end
91
+ end
92
+
93
+ def create_non_belongs_to_associations(record, data)
94
+ filter_non_belongs_to_associations(data).each do |association_data|
95
+ process_associations_content(association_data[:content], relation: record,
96
+ relation_name: association_data[:inverse])
97
+ end
98
+ end
99
+
100
+ def filter_belongs_to_associations(data)
101
+ data[:associations].select { |a| a[:kind] == 'belongs_to' }
102
+ end
103
+
104
+ def filter_non_belongs_to_associations(data)
105
+ data[:associations].reject { |a| a[:kind] == 'belongs_to' }
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveAdmin
4
+ module Exportable
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActiveAdmin::Exportable do
6
+ describe 'extends ResourceDSL' do
7
+ it 'by adding #exportable' do
8
+ dsl = ActiveAdmin::ResourceDSL
9
+
10
+ expect(dsl.public_instance_methods).to include(:exportable)
11
+ end
12
+ end
13
+
14
+ it 'enables form-based exportion by default' do
15
+ dsl = ActiveAdmin::ResourceDSL.new(double('config'))
16
+
17
+ expect(dsl).to receive(:enable_resource_exportion_via_form)
18
+
19
+ dsl.exportable
20
+ end
21
+
22
+ it 'enables save-based exportion with option `via: :save`' do
23
+ dsl = ActiveAdmin::ResourceDSL.new(double('config'))
24
+
25
+ expect(dsl).to receive(:enable_resource_exportion_via_save)
26
+
27
+ dsl.exportable(via: :save)
28
+ end
29
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_admin/exportable'
4
+
5
+ RSpec.configure do |config|
6
+ # These two settings work together to allow you to limit a spec run
7
+ # to individual examples or groups you care about by tagging them with
8
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
9
+ # get run.
10
+ config.filter_run :focus
11
+ config.run_all_when_everything_filtered = true
12
+
13
+ # Many RSpec users commonly either run the entire suite or an individual
14
+ # file, and it's useful to allow more verbose output when running an
15
+ # individual spec file.
16
+ if config.files_to_run.one?
17
+ # Use the documentation formatter for detailed output,
18
+ # unless a formatter has already been configured
19
+ # (e.g. via a command-line flag).
20
+ config.default_formatter = 'doc'
21
+ end
22
+
23
+ # Run specs in random order to surface order dependencies. If you find an
24
+ # order dependency and want to debug it, you can fix the order by providing
25
+ # the seed, which is printed after each run.
26
+ # --seed 1234
27
+ config.order = :random
28
+
29
+ # Seed global randomization in this process using the `--seed` CLI option.
30
+ # Setting this allows you to use `--seed` to deterministically reproduce
31
+ # test failures related to randomization by passing the same `--seed` value
32
+ # as the one that triggered the failure.
33
+ Kernel.srand config.seed
34
+
35
+ config.expect_with :rspec do |expectations|
36
+ expectations.syntax = :expect
37
+ end
38
+
39
+ config.mock_with :rspec do |mocks|
40
+ mocks.syntax = :expect
41
+ mocks.verify_partial_doubles = true
42
+ end
43
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_admin-exportable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Wagner Caixeta
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-05-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activeadmin
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sass-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Allow user to export/import of ActiveRecord records and associated records
98
+ in ActiveAdmin.
99
+ email:
100
+ - wagner.caixeta@gmail.com.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - CHANGELOG.md
107
+ - Gemfile
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - active_admin-exportable.gemspec
112
+ - app/admin/exportable/import.rb
113
+ - lib/active_admin/exportable.rb
114
+ - lib/active_admin/exportable/engine.rb
115
+ - lib/active_admin/exportable/exporter.rb
116
+ - lib/active_admin/exportable/importer.rb
117
+ - lib/active_admin/exportable/version.rb
118
+ - spec/exportable_spec.rb
119
+ - spec/spec_helper.rb
120
+ homepage: https://github.com/zorab47/active_admin-exportable
121
+ licenses:
122
+ - MIT
123
+ metadata: {}
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubygems_version: 3.2.17
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: A export/import tool for ActiveAdmin.
143
+ test_files:
144
+ - spec/exportable_spec.rb
145
+ - spec/spec_helper.rb