importable_attachments 0.0.13

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