csv_import 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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