rails_admin_import_no_encoding 0.1.0

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.
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'rubygems/tasks'
4
+ Gem::Tasks.new
5
+
6
+ # Piggyback off the Rails Admin rake tasks to set up the CI environment
7
+ spec = Gem::Specification.find_by_name 'rails_admin'
8
+ Dir["#{spec.gem_dir}/lib/tasks/*.rake"].each { |rake| load rake }
9
+
10
+ require 'rspec/core/rake_task'
11
+ RSpec::Core::RakeTask.new(:spec)
12
+
13
+ task test: :spec
14
+
15
+ task :default do
16
+ system("bundle exec rake spec")
17
+ end
@@ -0,0 +1,18 @@
1
+ - if @results && @results[:success].any?
2
+ .alert.alert-success.form-horizontal.denser
3
+ %fieldset
4
+ %legend
5
+ %i.icon-chevron-right
6
+ = @results[:success_message]
7
+ %ul.control-group{style: 'display: none'}
8
+ - @results[:success].each do |message|
9
+ %li= message
10
+ - if @results && @results[:error].any?
11
+ .alert.alert-danger.form-horizontal.denser
12
+ %fieldset
13
+ %legend
14
+ %i.icon-chevron-down
15
+ = @results[:error_message]
16
+ %ul.control-group
17
+ - @results[:error].each do |message|
18
+ %li= message
@@ -0,0 +1,10 @@
1
+ - if fields.any?
2
+ .form-group.control-group
3
+ %label.col-sm-2.control-label= t("admin.import.#{section}")
4
+ .col-sm-10.controls
5
+ %ul.list-unstyled
6
+ - fields.each do |field|
7
+ %li
8
+ %label= capitalize_first_letter(field.label)
9
+ %p.help-block= t("admin.import.help.#{section}")
10
+
@@ -0,0 +1,69 @@
1
+ = render "results"
2
+
3
+ = form_tag import_path(@abstract_model), :multipart => true, class: 'form-horizontal denser' do
4
+
5
+ %input{name: "send_data", type: "hidden", value: "true"}/
6
+ %fieldset
7
+ %legend
8
+ %i.icon-chevron-down
9
+ = t('admin.import.legend.fields')
10
+
11
+ = render "section", section: "model_fields", fields: @import_model.model_fields
12
+ = render "section", section: "association_fields", fields: @import_model.association_fields
13
+
14
+ %fieldset
15
+ %legend
16
+ %i.icon-chevron-down
17
+ = t('admin.import.legend.upload')
18
+ .form-group.control-group
19
+ %label.col-sm-2.control-label{for: "file"}= t("admin.import.file")
20
+ .col-sm-10.controls
21
+ = file_field_tag :file, :class => "form-control"
22
+ %p.help-block= t('admin.import.help.file_limit', limit: RailsAdminImport.config.line_item_limit)
23
+ .form-group.control-group
24
+ %label.col-sm-2.control-label{for: "encoding"}= t("admin.import.encoding")
25
+ .col-sm-10.controls
26
+ = select_tag 'encoding',
27
+ options_for_select(Encoding.name_list.sort),
28
+ include_blank: true, data: { enumeration: true }
29
+ %p.help-block= t('admin.import.help.encoding', name: 'UTF-8')
30
+ .form-group.control-group
31
+ %label.col-sm-2.control-label= t("admin.import.update_if_exists")
32
+ .col-sm-10.controls
33
+ = check_box_tag :update_if_exists, '1', RailsAdminImport.config.update_if_exists, :class => "form-control"
34
+ %p.help-block= t('admin.import.help.update_if_exists')
35
+ .form-group.control-group
36
+ %label.col-sm-2.control-label{for: "update_lookup"}= t("admin.import.update_lookup")
37
+ .col-sm-10.controls
38
+ = select_tag 'update_lookup',
39
+ options_for_select(@import_model.update_lookup_field_names,
40
+ Array.wrap(@import_model.config.mapping_key).map(&:to_s)),
41
+ multiple: true,
42
+ data: { enumeration: true }
43
+
44
+ - unless @import_model.association_fields.empty?
45
+ %fieldset
46
+ %legend
47
+ %i.icon-chevron-down
48
+ = t('admin.import.legend.mapping')
49
+
50
+ - @import_model.association_fields.each do |field|
51
+ .form-group.control-group
52
+ %label.col-sm-2.control-label
53
+ = capitalize_first_letter(field.label)
54
+ = t("admin.import.mapping")
55
+ .col-sm-10.controls
56
+ = select_tag "associations[#{field.name}]",
57
+ options_for_select(@import_model.associated_model_fields(field),
58
+ Array.wrap(@import_model.associated_config(field).mapping_key).first.to_s),
59
+ data: { enumeration: true }
60
+
61
+ %br
62
+ .form-actions
63
+ %input{type: :hidden, name: 'return_to', value: (request.params[:return_to].presence || request.referer)}
64
+ %button.btn.btn-primary{type: "submit", name: "commit", data: {disable_with: "Uploading..."} }
65
+ %i.icon-white.icon-ok
66
+ = t("admin.form.save")
67
+ %button.btn{type: "submit", name: "_continue"}
68
+ %i.icon-remove
69
+ = t("admin.form.cancel")
@@ -0,0 +1,3 @@
1
+ See the [community contributed translation section of the README](https://github.com/stephskardal/rails_admin_import#community-contributed-translations) for more languages.
2
+
3
+ To contribute a new translation, please put it in a gist and submit a pull request to link your translation in the README.
@@ -0,0 +1,50 @@
1
+
2
+ en:
3
+ admin:
4
+ actions:
5
+ import:
6
+ title: "Import"
7
+ menu: "Import"
8
+ breadcrumb: "Import"
9
+ link: "Import"
10
+ bulk_link: "Import"
11
+ done: "Imported"
12
+ import:
13
+ model_fields: "Model fields"
14
+ association_fields: "Association fields"
15
+
16
+ file: "Data file"
17
+ missing_file: "You must select a file"
18
+ format: "File format"
19
+ invalid_format: "Invalid import format."
20
+ missing_update_lookup: "Your file must contain a column for the 'Update lookup field' you selected."
21
+ invalid_json: "The JSON data should be an array of records or an object with a key '%{root_key}' set to an array of records"
22
+ update_if_exists: "Update if exists"
23
+ update_lookup: "Update lookup field(s)"
24
+ mapping: "mapping"
25
+ encoding: "Encoding"
26
+ legend:
27
+ fields: "Fields to import"
28
+ upload: "Upload file"
29
+ mapping: "Related fields mapping"
30
+ import_success:
31
+ create: "Created %{name}"
32
+ update: "Updated %{name}"
33
+ import_error:
34
+ create: "Failed to create %{name}: %{error}"
35
+ update: "Failed to update %{name}: %{error}"
36
+ general: "Error during import: %{error}"
37
+ line_item_limit: "Please limit upload file to %{limit} line items."
38
+ old_import_hook: >
39
+ The import hook %{model}.%{method} should take only 1 argument.
40
+ Data may not imported correctly.
41
+ See Upgrading section readme in Rails Admin Import.
42
+ association_not_found: "Association not found. %{error}"
43
+ help:
44
+ model_fields: "The fields above may be included in the import file."
45
+ association_fields: >
46
+ These fields map to other tables in the database, lookup via attribute selected below.
47
+ For "many" associations, you may include multiple columns with the same header in the CSV file.
48
+ update_if_exists: "Update records found with the lookup field below instead of creating new records"
49
+ file_limit: "Please limit upload file to %{limit} line items."
50
+ encoding: "Choose file encoding. Leave empty to auto-detect. Ignored for JSON."
@@ -0,0 +1,46 @@
1
+ require "rails_admin/config/actions"
2
+
3
+ module RailsAdmin
4
+ module Config
5
+ module Actions
6
+ class Import < Base
7
+ RailsAdmin::Config::Actions.register(self)
8
+
9
+ register_instance_option :collection do
10
+ true
11
+ end
12
+
13
+ register_instance_option :http_methods do
14
+ [:get, :post]
15
+ end
16
+
17
+ register_instance_option :controller do
18
+ proc do
19
+ @import_model = RailsAdminImport::ImportModel.new(@abstract_model)
20
+
21
+ if request.post?
22
+ format = RailsAdminImport::Formats.from_file(params[:file])
23
+ record_importer = RailsAdminImport::Formats.for(
24
+ format, @import_model, params)
25
+
26
+ if record_importer.valid?
27
+ importer = RailsAdminImport::Importer.new(
28
+ @import_model, params)
29
+
30
+ @results = importer.import(record_importer.each)
31
+ else
32
+ flash[:error] = record_importer.error
33
+ end
34
+ end
35
+
36
+ render action: @action.template_name
37
+ end
38
+ end
39
+
40
+ register_instance_option :link_icon do
41
+ "icon-folder-open"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,42 @@
1
+ module RailsAdminImport
2
+ module Config
3
+ class LegacyModel
4
+ attr_reader :model_name
5
+ def initialize(model_name)
6
+ @model_name = model_name
7
+ end
8
+
9
+ def label(_value)
10
+ # Ignored now
11
+ # RailsAdmin object_label_method will be used
12
+ end
13
+
14
+ def mapping_key(value)
15
+ config = RailsAdmin.config(model_name)
16
+ config.mapping_key(value)
17
+ end
18
+
19
+ def excluded_fields(values)
20
+ config = RailsAdmin.config(model_name)
21
+
22
+ # Call appropriate Rails Admin field list methods
23
+ config.import do
24
+ include_all_fields
25
+ exclude_fields *values
26
+ end
27
+ end
28
+
29
+ def extra_fields(values)
30
+ config = RailsAdmin.config(model_name)
31
+
32
+ # Call appropriate Rails Admin field list methods
33
+ config.import do
34
+ include_all_fields
35
+ values.each do |value|
36
+ field value
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,34 @@
1
+ require "rails_admin/config/sections/base"
2
+
3
+ module RailsAdmin
4
+ module Config
5
+ module Sections
6
+ # Configuration of the navigation view
7
+ class Import < RailsAdmin::Config::Sections::Base
8
+ register_instance_option(:mapping_key) do
9
+ :name
10
+ end
11
+
12
+ register_instance_option(:mapping_key_list) do
13
+ []
14
+ end
15
+
16
+ register_instance_option(:default_excluded_fields) do
17
+ [:id, :_id, :created_at, :updated_at, :c_at, :u_at, :deleted_at]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ section = RailsAdmin::Config::Sections::Import
25
+ name = :import
26
+
27
+ # Manually add to Rails Admin as a model configuration section until
28
+ # there is a better API to do this
29
+ RailsAdmin::Config::Model.send(:define_method, name) do |&block|
30
+ @sections = {} unless @sections
31
+ @sections[name] = section.new(self) unless @sections[name]
32
+ @sections[name].instance_eval(&block) if block
33
+ @sections[name]
34
+ end
@@ -0,0 +1,46 @@
1
+ require "rails_admin_import/config/legacy_model"
2
+
3
+ module RailsAdminImport
4
+ module Config
5
+ class << self
6
+ attr_accessor :logging
7
+ attr_accessor :line_item_limit
8
+ attr_accessor :rollback_on_error
9
+ attr_accessor :update_if_exists
10
+ attr_accessor :header_converter
11
+ attr_accessor :csv_options
12
+
13
+ # Default is to downcase headers and add underscores to convert into attribute names
14
+ HEADER_CONVERTER = lambda do |header|
15
+ # check for nil/blank headers
16
+ next if header.blank?
17
+ header.parameterize.underscore
18
+ end
19
+
20
+ def model(model_name, &block)
21
+ unless @deprecation_shown
22
+ warn "RailsAdminImport::Config#model is deprecated. " \
23
+ "Add a import section for your model inside the rails_admin " \
24
+ "config block. See the Readme.md for more details"
25
+ @deprecation_shown = true
26
+ end
27
+ legacy_config = RailsAdminImport::Config::LegacyModel.new(model_name)
28
+ legacy_config.instance_eval(&block) if block
29
+ legacy_config
30
+ end
31
+
32
+ # Reset all configurations to defaults.
33
+ def reset
34
+ @logging = false
35
+ @line_item_limit = 1000
36
+ @rollback_on_error = false
37
+ @update_if_exists = false
38
+ @header_converter = HEADER_CONVERTER
39
+ @csv_options = {}
40
+ end
41
+ end
42
+
43
+ # Set default values for configuration options on load
44
+ self.reset
45
+ end
46
+ end
@@ -0,0 +1,3 @@
1
+ require "rails_admin_import"
2
+ require "rchardet"
3
+ require "simple_xlsx_reader"
@@ -0,0 +1,4 @@
1
+ module RailsAdminImport
2
+ class Engine < Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,81 @@
1
+ require "csv"
2
+
3
+ module RailsAdminImport
4
+ module Formats
5
+ class CSVImporter < FileImporter
6
+ Formats.register(:csv, self)
7
+ Formats.register(:CSV, self)
8
+
9
+ autoload :CharDet, "rchardet"
10
+
11
+ def initialize(import_model, params)
12
+ super
13
+ @encoding = params[:encoding]
14
+ @header_converter = RailsAdminImport.config.header_converter
15
+ end
16
+
17
+ # A method that yields a hash of attributes for each record to import
18
+ def each_record
19
+ CSV.foreach(filename, csv_options) do |row|
20
+ attr = convert_to_attributes(row)
21
+ yield attr unless attr.all? { |field, value| value.blank? }
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def csv_options
28
+ defaults = RailsAdminImport.config.csv_options
29
+ options = {
30
+ headers: true,
31
+ header_converters: @header_converter,
32
+ encoding: encoding,
33
+ }
34
+
35
+ defaults.merge(options)
36
+ end
37
+
38
+ def encoding
39
+ from_encoding =
40
+ if !@encoding.blank?
41
+ @encoding
42
+ else
43
+ detect_encoding
44
+ end
45
+
46
+ to_encoding = import_model.abstract_model.encoding
47
+
48
+ if from_encoding && from_encoding != to_encoding
49
+ "#{from_encoding}:#{to_encoding}"
50
+ else
51
+ nil
52
+ end
53
+ end
54
+
55
+ def detect_encoding
56
+ # Su: Remove CharlockHolmes since it require to another software http://site.icu-project.org/home
57
+ # which is not available on server
58
+ # charset = CharlockHolmes::EncodingDetector.detect File.read(filename)
59
+ # if charset[:confidence] > 0.6
60
+ # from_encoding = charset[:encoding]
61
+ # from_encoding = "UTF-8" if from_encoding == "ascii"
62
+ # end
63
+ from_encoding = "UTF-8"
64
+ from_encoding
65
+ end
66
+
67
+ def convert_to_attributes(row)
68
+ row.each_with_object({}) do |(field, value), record|
69
+ next if field.blank?
70
+ field = field.to_sym
71
+ if import_model.has_multiple_values?(field)
72
+ field = import_model.pluralize_field(field)
73
+ (record[field] ||= []) << value
74
+ else
75
+ record[field] = value
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end