csv_import 0.0.1

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.
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
6
+ log
7
+ spec/fake/public
8
+ spec/fake/tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in csv_import.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2009 jarrett (https://github.com/jarrett)
2
+ Copyright (c) 2010-2011 mobalean LLC
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,43 @@
1
+ # CsvImport
2
+
3
+ This Rails plugin provides a controller method called each_csv_row and
4
+ an accompanying helper called csv_form.
5
+
6
+ By default, when each_csv_row is called, any exceptions raised in the
7
+ block will be rescued. The rows that triggered the exceptions will
8
+ then be displayed in a table as part of the output from csv_form.
9
+
10
+ You can turn off rescuing by calling each_csv_row(false).
11
+
12
+ Note that we have adapted this version to our needs for [Doorkeeper](http://www.doorkeeperhq.com/), and we welcome any additions to make it more generic.
13
+
14
+ [ドアキーパー](http://www.doorkeeper.jp/)でも利用するので、日本語対応もできます!
15
+
16
+ ## Compatibility
17
+
18
+ * Ruby 1.9
19
+ * Rails 3
20
+
21
+ ## Usage
22
+
23
+ # app/controllers/members_controller.rb
24
+
25
+ class MembersController < ActionController::Base
26
+ include CsvImport
27
+
28
+ def create
29
+ each_csv_row do |row|
30
+ Member.create!(row)
31
+ end
32
+ end
33
+ end
34
+
35
+ # app/views/members/index.html.erb
36
+
37
+ <h1>Import Members</h1>
38
+
39
+ <%= csv_form members_path do %>
40
+
41
+ <!-- whatever you put in the optional
42
+ block will appear at the end of the form -->
43
+ <% end %>
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,12 @@
1
+ require 'haml'
2
+ module CsvHelper
3
+ # The optional block allows you to pass in extra HTML that will be inserted after the CSV form fields but before the submit button.
4
+ def csv_form(url_for_options = {}, &block)
5
+ if block_given?
6
+ other_html = capture(&block)
7
+ else
8
+ other_html = nil
9
+ end
10
+ render :partial => 'csv_import/csv', :locals => {:url_for_options => url_for_options, :other_html => other_html}
11
+ end
12
+ end
@@ -0,0 +1,34 @@
1
+ = form_tag url_for_options, {:multipart => true} do
2
+ %p
3
+ = I18n.t :upload_label, :scope => :csv_import
4
+ = file_field_tag 'csv'
5
+ %p
6
+ = check_box_tag :csv_ignore_unknown_columns, true, false
7
+ %label{:for => 'csv_ignore_unknown_columns'}= I18n.t :ignore_unknown_columns_label, :scope => :csv_import
8
+ %div.columns= other_html
9
+ %p= submit_tag I18n.t(:submit_button, :scope => :csv_import), :class => 'button'
10
+
11
+ - if @rows_imported && ! @imported
12
+ %h2= I18n.t :import_faild, :scope => 'csv_import.errors'
13
+ - if @bad_csv
14
+ %p= I18n.t :bad_csv, :scope => 'csv_import.errors'
15
+ - else
16
+ %p= I18n.t :bad_rows, :scope => 'csv_import.errors', :bad_rows_length => @bad_rows.length, :rows_imported => @rows_imported
17
+ %p= I18n.t :exist_bad_rows, :scope => 'csv_import.errors'
18
+ - if @unknown_headers.any?
19
+ %h3= I18n.t :unknown_columns, :scope => 'csv_import.errors'
20
+ %p
21
+ = I18n.t :following_unknown_columns, :scope => 'csv_import.errors'
22
+ = @unknown_headers.map{|header| "&quot;#{h(header)}&quot;"}.join(", ").html_safe
23
+
24
+ - if @bad_rows.any?
25
+ %h3= I18n.t :bad_rows_in_uploaded_csv, :scope => 'csv_import.errors'
26
+ - @headers = @bad_rows.first.headers
27
+ %table
28
+ %tr
29
+ - @headers.each do |field_name|
30
+ %th= field_name
31
+ - @bad_rows.each_with_index do |row, row_number|
32
+ %tr{:class => cycle('even', 'odd')}
33
+ - @headers.each do |field_name|
34
+ %td= row[field_name].to_s
@@ -0,0 +1,14 @@
1
+ en:
2
+ csv_import:
3
+ upload_label: 'Upload CSV file:'
4
+ ignore_unknown_columns_label: 'Ignore all unknown columns in uploaded CSV'
5
+ submit_button: 'Import'
6
+
7
+ errors:
8
+ import_faild: 'Import Failed'
9
+ bad_csv: 'The uploaded file contained severe errors and could not be processed. Please make sure it is formatted correctly and contains headers.'
10
+ bad_rows: '%{bad_rows_length} rows failed to import. %{rows_imported} rows would have been imported successfully.'
11
+ exist_bad_rows: 'Anytime there are bad rows, the entire import gets cancelled. This is so that you can make corrections and re-run the import without manually rolling back the previous attempt.'
12
+ unknown_columns: 'Unknown columns in CSV'
13
+ following_unknown_columns: 'The following columns are not known: '
14
+ bad_rows_in_uploaded_csv: 'Bad rows in uploaded CSV'
@@ -0,0 +1,14 @@
1
+ ja:
2
+ csv_import:
3
+ upload_label: 'CSVファイルのアップロード:'
4
+ ignore_unknown_columns_label: 'アップロードされたCSVファイルに、不明な欄があった場合、無視する'
5
+ submit_button: 'インポート'
6
+
7
+ errors:
8
+ import_faild: 'インポートに失敗しました'
9
+ bad_csv: 'CSVファイルにエラーがあったため、アップロードに失敗しました。CSVのフォーマット、値などをご確認のうえ、再度アップロードお願いいたします。'
10
+ bad_rows: '%{bad_rows_length}列のインポートに失敗し、%{rows_imported}列のインポートに成功しました。'
11
+ exist_bad_rows: 'インポートに失敗した場合、全てのインポートはキャンセルされます。CSVファイルの修正後、再度アップロードしてください。'
12
+ unknown_columns: '不明な欄'
13
+ following_unknown_columns: '次の欄は不明です: '
14
+ bad_rows_in_uploaded_csv: '不正な列'
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "csv_import/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "csv_import"
7
+ s.version = CsvImport::VERSION
8
+ s.authors = ["Paul McMahon"]
9
+ s.email = ["paul@mobalean.com"]
10
+ s.homepage = "http://www.mobalean.com"
11
+ s.summary = %q{Easy CSV importing in Rails}
12
+ s.description = %q{Use this Rails 3 plugin to easily import data via csv files}
13
+
14
+ s.rubyforge_project = "csv_import"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'rails', '~> 3.0'
22
+ s.add_dependency 'haml', '~> 3.1'
23
+
24
+ s.add_development_dependency 'rspec', '~> 2.5.0'
25
+ s.add_development_dependency 'steak'
26
+ s.add_development_dependency 'sqlite3'
27
+ s.add_development_dependency 'launchy'
28
+ end
@@ -0,0 +1,55 @@
1
+ require 'csv'
2
+ require 'rails'
3
+
4
+ # Include this in a controller
5
+ module CsvImport
6
+ class Engine < Rails::Engine
7
+ end
8
+ DEFAULT_PARSE_OPTS = { :headers => true, :header_converters => :symbol }
9
+
10
+ private
11
+
12
+ def each_csv_row(opts = {})
13
+ @rows_imported = 0
14
+ @bad_csv = false
15
+ @bad_rows = []
16
+ @unknown_headers = Set.new
17
+ @imported = false
18
+
19
+ if request.post?
20
+ ActiveRecord::Base.transaction do
21
+ ::Rails.logger.info("starting csv import")
22
+ valid_headers = opts.delete(:valid_headers)
23
+
24
+ begin
25
+ CSV.parse(params[:csv].read.force_encoding("UTF-8"), DEFAULT_PARSE_OPTS.merge(opts)) do |row|
26
+ begin
27
+ row_data = row.to_hash
28
+ if valid_headers
29
+ row_data.delete_if {|header, value| ! valid_headers.include?(header) }
30
+ @unknown_headers.merge(row.headers - row_data.keys)
31
+ end
32
+ obj = yield row_data
33
+ obj.save! if obj && (obj.new_record? || obj.changed?)
34
+ @rows_imported += 1
35
+ rescue ActiveRecord::ActiveRecordError, ActiveRecord::UnknownAttributeError => e
36
+ row[:error] = e
37
+ @bad_rows << row
38
+ end
39
+ end
40
+
41
+ if @bad_rows.empty? && (@unknown_headers.empty? || params[:csv_ignore_unknown_columns])
42
+ @imported = true
43
+ end
44
+ rescue => e
45
+ @bad_csv = true
46
+ end
47
+
48
+ unless @imported
49
+ ::Rails.logger.info("rolling back csv import, contained errors")
50
+ raise ActiveRecord::Rollback
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,3 @@
1
+ module CsvImport
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+ require "spec_helper"
3
+
4
+ feature "import csv" do
5
+ scenario "with only ascii" do
6
+ visit members_path
7
+ attach_file 'csv', File.join(File.dirname(__FILE__), 'fixtures/ascii.csv')
8
+ click_button "Import"
9
+ page.find("td:first").text.should == "Paul McMahon"
10
+ page.find("td:last").text.should == "paul@mobalean.com"
11
+ end
12
+
13
+ scenario "with only utf-8" do
14
+ visit members_path
15
+ attach_file 'csv', File.join(File.dirname(__FILE__), 'fixtures/utf-8.csv')
16
+ click_button "Import"
17
+ page.find("td:first").text.should == "ポール"
18
+ page.find("td:last").text.should == "paul@mobalean.com"
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ require 'rails'
2
+ require 'active_record'
3
+ require 'action_controller/railtie'
4
+ require 'action_view/railtie'
5
+
6
+ ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
7
+ ActiveRecord::Base.establish_connection('test')
8
+
9
+ app = Class.new(Rails::Application)
10
+ app.config.root = File.dirname(__FILE__)
11
+ app.config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
12
+ app.config.session_store :cookie_store, :key => "_myapp_session"
13
+ app.config.active_support.deprecation = :log
14
+ app.config.action_dispatch.show_exceptions = false
15
+
16
+ app.initialize!
17
+
18
+ app.routes.draw do
19
+ resources :members
20
+ end
21
+ Class.new(ActiveRecord::Migration) do
22
+ def self.up
23
+ create_table(:members) {|t| t.string :email; t.string :name }
24
+ add_index :members, :email, :unique => true
25
+ end
26
+ end.up
27
+
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -0,0 +1,15 @@
1
+ class MembersController < ApplicationController
2
+ include CsvImport
3
+ def index
4
+ @members = Member.all
5
+ end
6
+ def create
7
+ each_csv_row do |row|
8
+ email = row[:email].to_s.strip
9
+ Member.find_or_create_by_email(email).tap do |member|
10
+ member.update_attributes!(row)
11
+ end
12
+ end
13
+ redirect_to action: :index
14
+ end
15
+ end
@@ -0,0 +1,2 @@
1
+ class Member < ActiveRecord::Base
2
+ end
@@ -0,0 +1,9 @@
1
+ = csv_form members_path
2
+ %table
3
+ %tr
4
+ %th Name
5
+ %th Email
6
+ - @members.each do |member|
7
+ %tr
8
+ %td= member.name
9
+ %td= member.email
@@ -0,0 +1,2 @@
1
+ name,email
2
+ Paul McMahon,paul@mobalean.com
@@ -0,0 +1,2 @@
1
+ name,email
2
+ ポール,paul@mobalean.com
@@ -0,0 +1,11 @@
1
+ $:.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'csv_import'
4
+ require File.expand_path(File.dirname(__FILE__) + "/fake/app")
5
+
6
+ require "steak"
7
+ require 'capybara/rspec'
8
+
9
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
10
+
11
+ require 'rspec/rails'
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: csv_import
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Paul McMahon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: &2156048980 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2156048980
25
+ - !ruby/object:Gem::Dependency
26
+ name: haml
27
+ requirement: &2156045560 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '3.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2156045560
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &2156044420 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 2.5.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2156044420
47
+ - !ruby/object:Gem::Dependency
48
+ name: steak
49
+ requirement: &2156043400 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2156043400
58
+ - !ruby/object:Gem::Dependency
59
+ name: sqlite3
60
+ requirement: &2156042300 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *2156042300
69
+ - !ruby/object:Gem::Dependency
70
+ name: launchy
71
+ requirement: &2156041660 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *2156041660
80
+ description: Use this Rails 3 plugin to easily import data via csv files
81
+ email:
82
+ - paul@mobalean.com
83
+ executables: []
84
+ extensions: []
85
+ extra_rdoc_files: []
86
+ files:
87
+ - .gitignore
88
+ - Gemfile
89
+ - MIT-LICENSE
90
+ - README.md
91
+ - Rakefile
92
+ - app/helpers/csv_helper.rb
93
+ - app/views/csv_import/_csv.html.haml
94
+ - config/locales/en.yml
95
+ - config/locales/ja.yml
96
+ - csv_import.gemspec
97
+ - lib/csv_import.rb
98
+ - lib/csv_import/version.rb
99
+ - spec/csv_import_spec.rb
100
+ - spec/fake/app.rb
101
+ - spec/fake/app/controllers/application_controller.rb
102
+ - spec/fake/app/controllers/members_controller.rb
103
+ - spec/fake/app/models/member.rb
104
+ - spec/fake/app/views/members/index.html.haml
105
+ - spec/fixtures/ascii.csv
106
+ - spec/fixtures/utf-8.csv
107
+ - spec/spec_helper.rb
108
+ homepage: http://www.mobalean.com
109
+ licenses: []
110
+ post_install_message:
111
+ rdoc_options: []
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ requirements: []
127
+ rubyforge_project: csv_import
128
+ rubygems_version: 1.8.10
129
+ signing_key:
130
+ specification_version: 3
131
+ summary: Easy CSV importing in Rails
132
+ test_files:
133
+ - spec/csv_import_spec.rb
134
+ - spec/fake/app.rb
135
+ - spec/fake/app/controllers/application_controller.rb
136
+ - spec/fake/app/controllers/members_controller.rb
137
+ - spec/fake/app/models/member.rb
138
+ - spec/fake/app/views/members/index.html.haml
139
+ - spec/fixtures/ascii.csv
140
+ - spec/fixtures/utf-8.csv
141
+ - spec/spec_helper.rb