importable_attachments 0.0.13

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.
Files changed (142) hide show
  1. data/.gitignore +24 -0
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +38 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.md +8 -0
  7. data/README.rdoc +3 -0
  8. data/Rakefile +29 -0
  9. data/app/assets/images/importable_attachments/.gitkeep +0 -0
  10. data/app/assets/images/importable_attachments/buttons/.htaccess +5 -0
  11. data/app/assets/images/importable_attachments/buttons/download_32.png +0 -0
  12. data/app/assets/images/importable_attachments/buttons/upload_32.png +0 -0
  13. data/app/assets/javascripts/importable_attachments/application.js +14 -0
  14. data/app/assets/javascripts/importable_attachments/attachments.coffee +41 -0
  15. data/app/assets/stylesheets/importable_attachments/application.css +14 -0
  16. data/app/assets/stylesheets/importable_attachments/attachments.css +4 -0
  17. data/app/assets/stylesheets/scaffold.css +56 -0
  18. data/app/controllers/importable_attachments/application_controller.rb +4 -0
  19. data/app/controllers/importable_attachments/attachments_controller.rb +190 -0
  20. data/app/controllers/importable_attachments/versions_controller.rb +87 -0
  21. data/app/helpers/importable_attachments/application_helper.rb +4 -0
  22. data/app/models/attachment.rb +24 -0
  23. data/app/models/importable_attachments/attachment.rb +143 -0
  24. data/app/models/importable_attachments/version.rb +50 -0
  25. data/app/validators/existing_class_validator.rb +17 -0
  26. data/app/validators/importable_attachments/csv_validator.rb +36 -0
  27. data/app/validators/importable_attachments/excel.rb +18 -0
  28. data/app/validators/importable_attachments/excel_validator.rb +18 -0
  29. data/app/views/importable_attachments/attachments/_attachment.html.haml +9 -0
  30. data/app/views/importable_attachments/attachments/_form.html.haml +22 -0
  31. data/app/views/importable_attachments/attachments/_nested_form.html.haml +20 -0
  32. data/app/views/importable_attachments/attachments/edit.html.haml +39 -0
  33. data/app/views/importable_attachments/attachments/index.html.haml +23 -0
  34. data/app/views/importable_attachments/attachments/index.xml.builder +23 -0
  35. data/app/views/importable_attachments/attachments/new.html.haml +10 -0
  36. data/app/views/importable_attachments/attachments/show.html.haml +43 -0
  37. data/app/views/importable_attachments/versions/_form.html.haml +25 -0
  38. data/app/views/importable_attachments/versions/edit.html.haml +7 -0
  39. data/app/views/importable_attachments/versions/index.html.haml +27 -0
  40. data/app/views/importable_attachments/versions/new.html.haml +5 -0
  41. data/app/views/importable_attachments/versions/show.html.haml +21 -0
  42. data/app/views/layouts/_version.html.haml +33 -0
  43. data/app/views/layouts/importable_attachments/application.html.haml +48 -0
  44. data/bin/set_lc.sh +47 -0
  45. data/config/database.yml +25 -0
  46. data/config/features/attachments.rb +8 -0
  47. data/config/features/mark_requirements.rb +3 -0
  48. data/config/features/smarter_dates.rb +3 -0
  49. data/config/features/versioning.rb +7 -0
  50. data/config/initializers/0_configuration.rb +7 -0
  51. data/config/initializers/formtastic.rb +76 -0
  52. data/config/initializers/generators.rb +10 -0
  53. data/config/initializers/paperclip.rb +27 -0
  54. data/config/locales/responders.en.yml +10 -0
  55. data/config/routes.rb +11 -0
  56. data/db/migrate/001_create_importable_attachments_versions.rb +14 -0
  57. data/db/migrate/100_create_attachments.rb +19 -0
  58. data/importable_attachments.gemspec +81 -0
  59. data/lib/generators/importable_attachments/install_generator.rb +66 -0
  60. data/lib/generators/importable_attachments/templates/features/attachments.rb.erb +7 -0
  61. data/lib/generators/importable_attachments/templates/features/versioning.rb +7 -0
  62. data/lib/generators/importable_attachments/templates/initializers/paperclip.rb +27 -0
  63. data/lib/importable_attachments/base.rb +108 -0
  64. data/lib/importable_attachments/blueprints.rb +9 -0
  65. data/lib/importable_attachments/engine.rb +8 -0
  66. data/lib/importable_attachments/importers/csv.rb +208 -0
  67. data/lib/importable_attachments/importers/excel.rb +37 -0
  68. data/lib/importable_attachments/importers.rb +7 -0
  69. data/lib/importable_attachments/version.rb +3 -0
  70. data/lib/importable_attachments.rb +9 -0
  71. data/lib/paperclip_processors/save_upload.rb +33 -0
  72. data/lib/tasks/importable_attachments_tasks.rake +4 -0
  73. data/script/rails +8 -0
  74. data/spec/attachments/books.csv +6 -0
  75. data/spec/attachments/books.txt +6 -0
  76. data/spec/attachments/books2.csv +4 -0
  77. data/spec/attachments/empty.csv +0 -0
  78. data/spec/attachments/failed_instances.csv +3 -0
  79. data/spec/attachments/invalid_headers.csv +3 -0
  80. data/spec/attachments/just_headers.csv +1 -0
  81. data/spec/attachments/mostly_empty.csv +2 -0
  82. data/spec/attachments/mostly_empty_copy.xls +0 -0
  83. data/spec/controllers/importable_attachments/attachments_controller_spec.rb +236 -0
  84. data/spec/controllers/importable_attachments/versions_controller_spec.rb +158 -0
  85. data/spec/dummy/README.rdoc +261 -0
  86. data/spec/dummy/Rakefile +7 -0
  87. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  88. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  89. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  90. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  91. data/spec/dummy/app/mailers/.gitkeep +0 -0
  92. data/spec/dummy/app/models/.gitkeep +0 -0
  93. data/spec/dummy/app/models/book.rb +13 -0
  94. data/spec/dummy/app/models/library.rb +54 -0
  95. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  96. data/spec/dummy/config/application.rb +65 -0
  97. data/spec/dummy/config/boot.rb +10 -0
  98. data/spec/dummy/config/database.yml +25 -0
  99. data/spec/dummy/config/environment.rb +5 -0
  100. data/spec/dummy/config/environments/development.rb +37 -0
  101. data/spec/dummy/config/environments/production.rb +67 -0
  102. data/spec/dummy/config/environments/test.rb +37 -0
  103. data/spec/dummy/config/initializers/0_configuration.rb +7 -0
  104. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  105. data/spec/dummy/config/initializers/inflections.rb +15 -0
  106. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  107. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  108. data/spec/dummy/config/initializers/session_store.rb +8 -0
  109. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  110. data/spec/dummy/config/locales/en.yml +5 -0
  111. data/spec/dummy/config/routes.rb +4 -0
  112. data/spec/dummy/config.ru +4 -0
  113. data/spec/dummy/db/migrate/101_create_libraries.rb +10 -0
  114. data/spec/dummy/db/migrate/102_create_books.rb +12 -0
  115. data/spec/dummy/db/schema.rb +57 -0
  116. data/spec/dummy/features/person_uploads_generic_file.feature +11 -0
  117. data/spec/dummy/features/step_definitions/person_uploads_generic_file_steps.rb +11 -0
  118. data/spec/dummy/features/step_definitions/web_steps.rb +211 -0
  119. data/spec/dummy/features/support/capybara.rb +6 -0
  120. data/spec/dummy/features/support/database_cleaner.rb +26 -0
  121. data/spec/dummy/features/support/developer_helpers.rb +47 -0
  122. data/spec/dummy/features/support/env.rb +53 -0
  123. data/spec/dummy/features/support/paths.rb +33 -0
  124. data/spec/dummy/features/support/poltergeist.rb +1 -0
  125. data/spec/dummy/features/support/selectors.rb +39 -0
  126. data/spec/dummy/features/support/transactional_fixtures.rb +14 -0
  127. data/spec/dummy/lib/assets/.gitkeep +0 -0
  128. data/spec/dummy/log/.gitkeep +0 -0
  129. data/spec/dummy/public/404.html +38 -0
  130. data/spec/dummy/public/422.html +38 -0
  131. data/spec/dummy/public/500.html +36 -0
  132. data/spec/dummy/public/favicon.ico +0 -0
  133. data/spec/dummy/script/rails +6 -0
  134. data/spec/dummy/spec/support/.gitkeep +0 -0
  135. data/spec/dummy/spec/support/paperclip.rb +1 -0
  136. data/spec/models/importable_attachments/attachment_spec.rb +177 -0
  137. data/spec/models/importable_attachments/library_spec.rb +155 -0
  138. data/spec/models/importable_attachments/version_spec.rb +25 -0
  139. data/spec/routing/importable_attachments/versions_routing_spec.rb +43 -0
  140. data/spec/spec.opts +5 -0
  141. data/spec/spec_helper.rb +30 -0
  142. metadata +737 -0
@@ -0,0 +1,53 @@
1
+ # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
2
+ # It is recommended to regenerate this file in the future when you upgrade to a
3
+ # newer version of cucumber-rails. Consider adding your own code to a new file
4
+ # instead of editing this one. Cucumber will automatically load all features/**/*.rb
5
+ # files.
6
+
7
+ require 'rubygems'
8
+
9
+ if defined?(IRB) && IRB.class.to_s == 'Class'
10
+ Object.send(:remove_const, :IRB)
11
+ require 'IRB'
12
+ require 'IRB/init'
13
+ require 'IRB/context'
14
+ require 'IRB/extend-command'
15
+ require 'IRB/locale'
16
+ end
17
+
18
+ begin
19
+ ; require 'ruby-debug'
20
+ rescue LoadError => err;
21
+ puts err;
22
+ end
23
+
24
+ begin
25
+ ; require 'pry'
26
+ if defined?(IRB) && IRB.class.to_s == 'Module'
27
+ Object.send(:remove_const, :IRB)
28
+ IRB = Pry
29
+ end
30
+ rescue LoadError => err;
31
+ end
32
+
33
+ require 'cucumber/rails'
34
+
35
+ # By default, any exception happening in your Rails application will bubble up
36
+ # to Cucumber so that your scenario will fail. This is a different from how
37
+ # your application behaves in the production environment, where an error page will
38
+ # be rendered instead.
39
+ #
40
+ # Sometimes we want to override this default behaviour and allow Rails to rescue
41
+ # exceptions and display an error page (just like when the app is running in production).
42
+ # Typical scenarios where you want to do this is when you test your error pages.
43
+ # There are two ways to allow Rails to rescue exceptions:
44
+ #
45
+ # 1) Tag your scenario (or feature) with @allow-rescue
46
+ #
47
+ # 2) Set the value below to true. Beware that doing this globally is not
48
+ # recommended as it will mask a lot of errors for you!
49
+ #
50
+ ActionController::Base.allow_rescue = false
51
+
52
+ require 'cucumber/rails/world'
53
+
@@ -0,0 +1,33 @@
1
+ module NavigationHelpers
2
+ # Maps a name to a path. Used by the
3
+ #
4
+ # When /^I go to (.+)$/ do |page_name|
5
+ #
6
+ # step definition in web_steps.rb
7
+ #
8
+ def path_to(page_name)
9
+ case page_name
10
+
11
+ when /^the home\s?page$/
12
+ '/'
13
+
14
+ # Add more mappings here.
15
+ # Here is an example that pulls values out of the Regexp:
16
+ #
17
+ # when /^(.*)'s profile page$/i
18
+ # user_profile_path(User.find_by_login($1))
19
+
20
+ else
21
+ begin
22
+ page_name =~ /^the (.*) page$/
23
+ path_components = $1.split(/\s+/)
24
+ self.send(path_components.push('path').join('_').to_sym)
25
+ rescue NoMethodError, ArgumentError
26
+ raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
27
+ "Now, go and add a mapping in #{__FILE__}"
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ World(NavigationHelpers)
@@ -0,0 +1 @@
1
+ Capybara.javascript_driver = :poltergeist
@@ -0,0 +1,39 @@
1
+ module HtmlSelectorsHelpers
2
+ # Maps a name to a selector. Used primarily by the
3
+ #
4
+ # When /^(.+) within (.+)$/ do |step, scope|
5
+ #
6
+ # step definitions in web_steps.rb
7
+ #
8
+ def selector_for(locator)
9
+ case locator
10
+
11
+ when "the page"
12
+ "html > body"
13
+
14
+ # Add more mappings here.
15
+ # Here is an example that pulls values out of the Regexp:
16
+ #
17
+ # when /^the (notice|error|info) flash$/
18
+ # ".flash.#{$1}"
19
+
20
+ # You can also return an array to use a different selector
21
+ # type, like:
22
+ #
23
+ # when /the header/
24
+ # [:xpath, "//header"]
25
+
26
+ # This allows you to provide a quoted selector as the scope
27
+ # for "within" steps as was previously the default for the
28
+ # web steps:
29
+ when /^"(.+)"$/
30
+ $1
31
+
32
+ else
33
+ raise "Can't find mapping from \"#{locator}\" to a selector.\n" +
34
+ "Now, go and add a mapping in #{__FILE__}"
35
+ end
36
+ end
37
+ end
38
+
39
+ World(HtmlSelectorsHelpers)
@@ -0,0 +1,14 @@
1
+ # If you set this to true, each scenario will run in a database transaction.
2
+ # You can still turn off transactions on a per-scenario basis, simply tagging
3
+ # a feature or scenario with the @no-txn tag. If you are using Capybara,
4
+ # tagging with @culerity or @javascript will also turn transactions off.
5
+ #
6
+ # If you set this to false, transactions will be off for all scenarios,
7
+ # regardless of whether you use @no-txn or not.
8
+ #
9
+ # Beware that turning transactions off will leave data in your database
10
+ # after each scenario, which can lead to hard-to-debug failures in
11
+ # subsequent scenarios. If you do this, we recommend you create a Before
12
+ # block that will explicitly put your database in a known state.
13
+ Cucumber::Rails::World.use_transactional_fixtures = true
14
+
File without changes
File without changes
@@ -0,0 +1,38 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style type="text/css">
6
+ body {
7
+ background-color: #fff;
8
+ color: #666;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ padding: 0 4em;
16
+ margin: 4em auto 0 auto;
17
+ border: 1px solid #ccc;
18
+ border-right-color: #999;
19
+ border-bottom-color: #999;
20
+ }
21
+
22
+ h1 {
23
+ font-size: 100%;
24
+ color: #f00;
25
+ line-height: 1.5em;
26
+ }
27
+ </style>
28
+ </head>
29
+
30
+ <body>
31
+ <!-- This file lives in public/404.html -->
32
+ <div class="dialog">
33
+ <h1>The page you were looking for doesn't exist.</h1>
34
+
35
+ <p>You may have mistyped the address or the page may have moved.</p>
36
+ </div>
37
+ </body>
38
+ </html>
@@ -0,0 +1,38 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body {
7
+ background-color: #fff;
8
+ color: #666;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ padding: 0 4em;
16
+ margin: 4em auto 0 auto;
17
+ border: 1px solid #ccc;
18
+ border-right-color: #999;
19
+ border-bottom-color: #999;
20
+ }
21
+
22
+ h1 {
23
+ font-size: 100%;
24
+ color: #f00;
25
+ line-height: 1.5em;
26
+ }
27
+ </style>
28
+ </head>
29
+
30
+ <body>
31
+ <!-- This file lives in public/422.html -->
32
+ <div class="dialog">
33
+ <h1>The change you wanted was rejected.</h1>
34
+
35
+ <p>Maybe you tried to change something you didn't have access to.</p>
36
+ </div>
37
+ </body>
38
+ </html>
@@ -0,0 +1,36 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body {
7
+ background-color: #fff;
8
+ color: #666;
9
+ text-align: center;
10
+ font-family: arial, sans-serif;
11
+ }
12
+
13
+ div.dialog {
14
+ width: 25em;
15
+ padding: 0 4em;
16
+ margin: 4em auto 0 auto;
17
+ border: 1px solid #ccc;
18
+ border-right-color: #999;
19
+ border-bottom-color: #999;
20
+ }
21
+
22
+ h1 {
23
+ font-size: 100%;
24
+ color: #f00;
25
+ line-height: 1.5em;
26
+ }
27
+ </style>
28
+ </head>
29
+
30
+ <body>
31
+ <!-- This file lives in public/500.html -->
32
+ <div class="dialog">
33
+ <h1>We're sorry, but something went wrong.</h1>
34
+ </div>
35
+ </body>
36
+ </html>
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
File without changes
@@ -0,0 +1 @@
1
+ require 'paperclip/matchers'
@@ -0,0 +1,177 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe ImportableAttachments::Attachment do
4
+ # :call-seq:
5
+ # mock_io_stream [:opts]
6
+ #
7
+ # yields a mock Paperclip::Attachment object
8
+
9
+ def mock_io_stream(opts = {})
10
+ attached_to = opts[:attach_to]
11
+ @io_stream = Paperclip::Attachment.new(:io_stream, attached_to,
12
+ {path: ::Configuration.for('attachments').path,
13
+ preserve_files: true, processors: [:save_upload]})
14
+ spec_dir = File.dirname(@io_stream.path).sub(/(?:\/\.?)?$/, "")
15
+ FileUtils.mkdir_p spec_dir unless File.directory? spec_dir
16
+ @io_stream
17
+ end
18
+
19
+ # :call-seq:
20
+ # mock_attachment [:opts]
21
+ #
22
+ # yields a mock Attachment object
23
+
24
+ def mock_attachment(opts = {})
25
+ lopts = {id: 27,
26
+ io_stream: nil,
27
+ io_stream_file_name: 'mostly_empty.csv',
28
+ io_stream_content_type: 'Test Content Type',
29
+ io_stream_file_size: 1,
30
+ io_stream_updated_at: DateTime.now,
31
+ revision_number: 1,
32
+ attachable_type: nil, attachable_id: nil, version: 1}
33
+ @attachment = mock_model(ImportableAttachments::Attachment, lopts.merge(opts))
34
+ @attachment.stubs(:io_stream).returns(mock_io_stream(:attach_to => @attachment))
35
+ FileUtils.cp @spec_file, @attachment.io_stream.path
36
+ @attachment
37
+ end
38
+
39
+ before :each do
40
+ #ActiveRecord::Base.send(:subclasses).each{|m|m.destroy_all}
41
+ @spec_file = Rails.root.join('spec', 'attachments', 'mostly_empty.csv')
42
+
43
+ mock_attachment
44
+ #Attachment.stubs(:find).with(@attachment.id.to_s).returns(@attachment)
45
+ end
46
+
47
+ context 'validations' do
48
+ it { should have_valid(:attachable_id).when(nil, 1, 2^64-1) }
49
+ it { should_not have_valid(:attachable_id).when(-1, 1.1) }
50
+
51
+ it { should have_valid(:attachable_type).when(nil, 'ImportableAttachments::Attachment') }
52
+ it { should_not have_valid(:attachable_type).when("Test \x0 data") }
53
+
54
+ it { should have_valid(:io_stream_file_name).when('Test data') }
55
+ it { should_not have_valid(:io_stream_file_name).when(nil, "Test \x0 data") }
56
+
57
+ it { should have_valid(:io_stream_content_type).when('Test data') }
58
+ it { should_not have_valid(:io_stream_content_type).when(nil, "Test \x0 data") }
59
+
60
+ it { should have_valid(:io_stream_updated_at).when(nil, Date.today) }
61
+ #it { should_not have_valid(:io_stream_updated_at).when("Test \x0 data") }
62
+
63
+ it 'should ensure the attachment exists' do
64
+ should validate_attachment_presence(:io_stream)
65
+ end
66
+
67
+ it 'should ensure the attachment is non-empty' do
68
+ should validate_attachment_size(:io_stream).greater_than(0)
69
+ end
70
+
71
+ it 'should require an :io_stream_file_name' do
72
+ attachment = ImportableAttachments::Attachment.new :io_stream => File.new(@spec_file, 'rb')
73
+ attachment.io_stream_file_name = nil
74
+ attachment.should_not be_valid
75
+ attachment.should have(1).error_on(:io_stream_file_name)
76
+ end
77
+
78
+ it 'should not allow odd characters in :io_stream_file_name' do
79
+ attachment = ImportableAttachments::Attachment.new :io_stream => File.new(@spec_file, 'rb')
80
+ attachment.io_stream_file_name = "file_path\b\b\b\b\bpath"
81
+ attachment.should_not be_valid
82
+ attachment.should have(1).error_on(:io_stream_file_name)
83
+ end
84
+ end
85
+
86
+ context 'expected behavior:' do
87
+ it 'should provide an :io_stream_content_type' do
88
+ attachment = ImportableAttachments::Attachment.new :io_stream => File.new(@spec_file, 'rb')
89
+ attachment.should be_valid
90
+ end
91
+
92
+ it 'should save the file to the filesystem' do
93
+ attachment = ImportableAttachments::Attachment.new :io_stream => File.new(@spec_file, 'rb')
94
+ attachment.save!
95
+ File.exist?(attachment.io_stream.path).should be_true
96
+ end
97
+
98
+ it 'should identify an unsaved file as nil' do
99
+ attachment = ImportableAttachments::Attachment.new :io_stream => File.new(@spec_file, 'rb')
100
+ attachment.magic_mime_type.should be_nil
101
+ end
102
+
103
+ it 'should identify the file mime_type as CSV' do
104
+ attachment = ImportableAttachments::Attachment.create! :io_stream => File.new(@spec_file, 'rb')
105
+ attachment.magic_mime_type.should == 'text/plain'
106
+ attachment.io_stream.content_type.should == 'text/csv'
107
+ end
108
+
109
+ it 'should provide an :io_stream_mime_type' do
110
+ attachment = ImportableAttachments::Attachment.new :io_stream => File.new(@spec_file, 'rb')
111
+ attachment.io_stream_mime_type.should be_a(MIME::Type)
112
+ end
113
+
114
+ it 'should save multiple versions of the file to the filesystem' do
115
+ with_versioning do
116
+ spec_file = Rails.root.join('spec', 'attachments', 'mostly_empty.csv')
117
+ attachment1 = ImportableAttachments::Attachment.new :io_stream => File.new(spec_file, 'rb')
118
+ attachment1.save!
119
+ File.exist?(attachment1.io_stream.path).should be_true
120
+ if ::Configuration.for('attachments').include_revision_in_filename
121
+ attachment1.io_stream.path.should match /mostly_empty\.1\.csv$/
122
+ else
123
+ attachment1.io_stream.path.should match /mostly_empty\.csv$/
124
+ end
125
+
126
+ #attachment1.io_stream = File.new(@spec_file,'rb')
127
+ ImportableAttachments::Attachment.stubs(:find).with(attachment1.id).returns(attachment1)
128
+ attachment2 = ImportableAttachments::Attachment.find(attachment1.id)
129
+ spec_file = Rails.root.join('spec', 'attachments', 'mostly_empty.csv')
130
+ attachment2.update_attributes :io_stream => File.new(spec_file, 'rb')
131
+ File.exist?(attachment2.io_stream.path).should be_true
132
+ if ::Configuration.for('attachments').include_revision_in_filename
133
+ attachment2.io_stream.path.should match /mostly_empty\.2\.csv$/
134
+ else
135
+ attachment1.io_stream.path.should match /mostly_empty\.csv$/
136
+ end
137
+ end
138
+ end
139
+
140
+ it 'should yield a revision_number' do
141
+ with_versioning do
142
+ spec_file = Rails.root.join('spec', 'attachments', 'mostly_empty.csv')
143
+ attachment1 = ImportableAttachments::Attachment.new :io_stream => File.new(spec_file, 'rb')
144
+ attachment1.save!
145
+ attachment1.revision_number.should == 1
146
+
147
+ #attachment1.io_stream = File.new(@spec_file,'rb')
148
+ ImportableAttachments::Attachment.stubs(:find).with(attachment1.id).returns(attachment1)
149
+ attachment2 = ImportableAttachments::Attachment.find(attachment1.id)
150
+ spec_file = Rails.root.join('spec', 'attachments', 'mostly_empty_copy.xls')
151
+ attachment2.update_attributes :io_stream => File.new(spec_file, 'rb')
152
+ attachment2.revision_number.should == 2
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ # == Schema Information
159
+ #
160
+ # Table name: attachments
161
+ #
162
+ # id :integer not null, primary key
163
+ # attachable_type :string(255)
164
+ # attachable_id :string(255)
165
+ # io_stream_file_name :string(255)
166
+ # io_stream_content_type :string(255)
167
+ # io_stream_file_size :integer
168
+ # io_stream_updated_at :datetime
169
+ # created_at :datetime not null
170
+ # updated_at :datetime not null
171
+ #
172
+ # Indexes
173
+ #
174
+ # idx_importable_attachments_on_attachable_type_and_id (attachable_type,attachable_id)
175
+ # index_attachments_on_io_stream_file_name (io_stream_file_name)
176
+ #
177
+
@@ -0,0 +1,155 @@
1
+ require 'spec_helper'
2
+
3
+ def spec_file(file_name)
4
+ Rails.root.join('spec', 'attachments', file_name)
5
+ end
6
+
7
+ describe Library do
8
+ before :each do
9
+ @spec_file = spec_file('books.csv')
10
+ end
11
+
12
+ context 'attachment validations' do
13
+ subject { Library.create(name: 'XYZ Library', address: '123 Main St.') }
14
+ it { subject.should have_valid(:attachment).when(nil, Attachment.new(io_stream: File.new(@spec_file))) }
15
+ it {
16
+ subject.should_not have_valid(:attachment).when(Attachment.new io_stream: File.new(Rails.root.join('spec', 'attachments', 'books.txt'))) }
17
+ end
18
+
19
+ context 'importing attachments' do
20
+ before :each do
21
+ @attachment = Attachment.new io_stream: File.new(@spec_file, 'rb')
22
+ end
23
+
24
+ subject { Library.create(name: 'XYZ Library', address: '123 Main St.') }
25
+
26
+ context 'in the right format' do
27
+ it 'should optionally allow an attachment' do
28
+ subject.attachment = @attachment
29
+ subject.attachment.should_not be_nil
30
+ subject.attachment.attachable_type.should == 'Library'
31
+ subject.attachment.io_stream_file_name.should == File.basename(@spec_file)
32
+ end
33
+
34
+ it 'should import a spreadsheet if it is in the right format' do
35
+ subject.books.should be_empty
36
+ lambda {
37
+ subject.attachment = @attachment
38
+ }.should change(subject.books, :count).by(5)
39
+ end
40
+ end
41
+
42
+ context 'wrong extension' do
43
+ before :each do
44
+ @spec_file = spec_file('books.txt')
45
+ end
46
+
47
+ it 'should not import a spreadsheet if it has the wrong extension' do
48
+ attachment = Attachment.new io_stream: File.new(@spec_file, 'rb')
49
+ subject.attachment = attachment
50
+ subject.should_not be_valid
51
+ end
52
+
53
+ it 'should not delete existing data if new upload has the wrong extension' do
54
+ subject.attachment = @attachment
55
+ attachment = Attachment.new io_stream: File.new(@spec_file, 'rb')
56
+ lambda {
57
+ subject.attachment = attachment
58
+ }.should_not change(subject.books, :count)
59
+ end
60
+
61
+ it 'should not register / acknowledge the file is still in the system' do
62
+ subject.attachment = @attachment
63
+ attachment = Attachment.new io_stream: File.new(@spec_file, 'rb')
64
+ lambda {
65
+ subject.attachment = attachment
66
+ }.should_not change(subject.attachment, :io_stream_file_name)
67
+ end
68
+ end
69
+
70
+ context 'invalid headers' do
71
+ before :each do
72
+ @spec_file = spec_file('invalid_headers.csv')
73
+ end
74
+
75
+ it 'should not import a spreadsheet if it has invalid headers' do
76
+ attachment = Attachment.new io_stream: File.new(@spec_file, 'rb')
77
+ subject.attachment = attachment
78
+ subject.should_not be_valid
79
+ end
80
+
81
+ it 'should not delete existing data if new upload has invalid headers' do
82
+ subject.attachment = @attachment
83
+ attachment = Attachment.new io_stream: File.new(@spec_file, 'rb')
84
+ lambda {
85
+ subject.attachment = attachment
86
+ }.should_not change(subject.books, :count)
87
+ end
88
+
89
+ it 'should not register / acknowledge the file is still in the system' do
90
+ subject.attachment = @attachment
91
+ attachment = Attachment.new io_stream: File.new(@spec_file, 'rb')
92
+ lambda {
93
+ subject.attachment = attachment
94
+ }.should_not change(subject.attachment, :io_stream_file_name)
95
+ end
96
+ end
97
+
98
+ context 'failed instances' do
99
+ before :each do
100
+ @spec_file = spec_file('failed_instances.csv')
101
+ end
102
+
103
+ it 'should not import a spreadsheet if it has failed instances' do
104
+ attachment = Attachment.new io_stream: File.new(@spec_file, 'rb')
105
+ subject.attachment = attachment
106
+ subject.should_not be_valid
107
+ end
108
+
109
+ it 'should not delete existing data if new upload has failed instances' do
110
+ subject.attachment = @attachment
111
+ attachment = Attachment.new io_stream: File.new(@spec_file, 'rb')
112
+ lambda {
113
+ subject.attachment = attachment
114
+ }.should_not change(subject.books, :count)
115
+ end
116
+
117
+ it 'should not register / acknowledge the file is still in the system' do
118
+ subject.attachment = @attachment
119
+ attachment = Attachment.new io_stream: File.new(@spec_file, 'rb')
120
+ lambda {
121
+ subject.attachment = attachment
122
+ }.should_not change(subject.attachment, :io_stream_file_name)
123
+ end
124
+ end
125
+
126
+ context 'updating when an attachment already exists with destructive import' do
127
+ it 'should delete the rows from old file and replace them with rows from new file' do
128
+ subject.attachment = @attachment
129
+ attachment = Attachment.new io_stream: File.new(spec_file('books2.csv'), 'rb')
130
+ lambda {
131
+ subject.attachment = attachment
132
+ }.should change(subject.books, :count).by(-2)
133
+ end
134
+ end
135
+
136
+ context 'assigning attachment to new record' do
137
+ subject { Library.new(name: 'XYZ Library', address: '123 Main St.') }
138
+
139
+ it 'should not import when the record is not persisted' do
140
+ lambda {
141
+ subject.attachment = @attachment
142
+ }.should_not change(subject.books, :count)
143
+ end
144
+
145
+ it 'should import upon saving the record' do
146
+ lambda {
147
+ subject.attachment = @attachment
148
+ subject.save
149
+ }.should change(subject.books, :count).by(5)
150
+ end
151
+ end
152
+ end
153
+
154
+ end
155
+
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe ImportableAttachments::Version do
4
+ # :call-seq:
5
+ # mock_version [:opts]
6
+ #
7
+ # yields a mock Version object
8
+
9
+ def mock_version(opts = {})
10
+ lopts = {:id => 27, :item_type => nil, :item_id => nil}
11
+ @version = mock_model(Version, lopts.merge(opts))
12
+ @version
13
+ end
14
+
15
+ before :each do
16
+ mock_version
17
+ end
18
+
19
+ context 'validations' do
20
+ it { should have_valid(:item_id).when(nil, 1, 'uniqueId', 'unique_id', 'unique.id') }
21
+
22
+ it { should have_valid(:item_type).when(nil, 'Attachment', 'ImportableAttachments::Attachment') }
23
+ it { should_not have_valid(:item_type).when("Test \x0 data") }
24
+ end
25
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ module ImportableAttachments
4
+ describe VersionsController do
5
+ context 'routing' do
6
+
7
+ before :each do
8
+ @routes = ::ImportableAttachments::Engine.routes
9
+
10
+ # https://github.com/rspec/rspec-rails/pull/539
11
+ assertion_instance.instance_variable_set(:@routes, ::ImportableAttachments::Engine.routes)
12
+ end
13
+
14
+ it 'routes to #index' do
15
+ get('/versions').should route_to('importable_attachments/versions#index')
16
+ end
17
+
18
+ it 'routes to #new' do
19
+ get('/versions/new').should route_to('importable_attachments/versions#new')
20
+ end
21
+
22
+ it 'routes to #show' do
23
+ get('/versions/1').should route_to('importable_attachments/versions#show', :id => '1')
24
+ end
25
+
26
+ it 'routes to #edit' do
27
+ get('/versions/1/edit').should route_to('importable_attachments/versions#edit', :id => '1')
28
+ end
29
+
30
+ it 'routes to #create' do
31
+ post('/versions').should route_to('importable_attachments/versions#create')
32
+ end
33
+
34
+ it 'routes to #update' do
35
+ put('/versions/1').should route_to('importable_attachments/versions#update', :id => '1')
36
+ end
37
+
38
+ it 'routes to #destroy' do
39
+ delete('/versions/1').should route_to('importable_attachments/versions#destroy', :id => '1')
40
+ end
41
+ end
42
+ end
43
+ end