jr-paperclip 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. checksums.yaml +7 -0
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  4. data/.github/ISSUE_TEMPLATE/custom.md +10 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. data/.github/workflows/reviewdog.yml +23 -0
  7. data/.github/workflows/test.yml +46 -0
  8. data/.gitignore +19 -0
  9. data/.qlty/.gitignore +7 -0
  10. data/.qlty/qlty.toml +89 -0
  11. data/.rubocop.yml +1060 -0
  12. data/Appraisals +29 -0
  13. data/CONTRIBUTING.md +85 -0
  14. data/Gemfile +17 -0
  15. data/LICENSE +25 -0
  16. data/NEWS +567 -0
  17. data/README.md +1083 -0
  18. data/RELEASING.md +17 -0
  19. data/Rakefile +52 -0
  20. data/bin/console +11 -0
  21. data/features/basic_integration.feature +85 -0
  22. data/features/migration.feature +29 -0
  23. data/features/rake_tasks.feature +62 -0
  24. data/features/step_definitions/attachment_steps.rb +121 -0
  25. data/features/step_definitions/html_steps.rb +15 -0
  26. data/features/step_definitions/rails_steps.rb +271 -0
  27. data/features/step_definitions/s3_steps.rb +16 -0
  28. data/features/step_definitions/web_steps.rb +106 -0
  29. data/features/support/env.rb +12 -0
  30. data/features/support/file_helpers.rb +34 -0
  31. data/features/support/fixtures/boot_config.txt +15 -0
  32. data/features/support/fixtures/gemfile.txt +5 -0
  33. data/features/support/fixtures/preinitializer.txt +20 -0
  34. data/features/support/paths.rb +28 -0
  35. data/features/support/rails.rb +39 -0
  36. data/features/support/selectors.rb +19 -0
  37. data/features/support/webmock_setup.rb +8 -0
  38. data/gemfiles/7.0.gemfile +20 -0
  39. data/gemfiles/7.1.gemfile +20 -0
  40. data/gemfiles/7.2.gemfile +20 -0
  41. data/gemfiles/8.0.gemfile +20 -0
  42. data/gemfiles/8.1.gemfile +20 -0
  43. data/lib/generators/paperclip/USAGE +8 -0
  44. data/lib/generators/paperclip/paperclip_generator.rb +36 -0
  45. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +15 -0
  46. data/lib/jr-paperclip.rb +1 -0
  47. data/lib/paperclip/attachment.rb +634 -0
  48. data/lib/paperclip/attachment_registry.rb +60 -0
  49. data/lib/paperclip/callbacks.rb +42 -0
  50. data/lib/paperclip/content_type_detector.rb +85 -0
  51. data/lib/paperclip/errors.rb +34 -0
  52. data/lib/paperclip/file_command_content_type_detector.rb +28 -0
  53. data/lib/paperclip/filename_cleaner.rb +15 -0
  54. data/lib/paperclip/geometry.rb +157 -0
  55. data/lib/paperclip/geometry_detector_factory.rb +45 -0
  56. data/lib/paperclip/geometry_parser_factory.rb +31 -0
  57. data/lib/paperclip/glue.rb +18 -0
  58. data/lib/paperclip/has_attached_file.rb +116 -0
  59. data/lib/paperclip/helpers.rb +60 -0
  60. data/lib/paperclip/interpolations/plural_cache.rb +18 -0
  61. data/lib/paperclip/interpolations.rb +205 -0
  62. data/lib/paperclip/io_adapters/abstract_adapter.rb +75 -0
  63. data/lib/paperclip/io_adapters/attachment_adapter.rb +56 -0
  64. data/lib/paperclip/io_adapters/data_uri_adapter.rb +22 -0
  65. data/lib/paperclip/io_adapters/empty_string_adapter.rb +19 -0
  66. data/lib/paperclip/io_adapters/file_adapter.rb +26 -0
  67. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +16 -0
  68. data/lib/paperclip/io_adapters/identity_adapter.rb +17 -0
  69. data/lib/paperclip/io_adapters/nil_adapter.rb +37 -0
  70. data/lib/paperclip/io_adapters/registry.rb +36 -0
  71. data/lib/paperclip/io_adapters/stringio_adapter.rb +36 -0
  72. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +44 -0
  73. data/lib/paperclip/io_adapters/uri_adapter.rb +78 -0
  74. data/lib/paperclip/locales/en.yml +18 -0
  75. data/lib/paperclip/locales/fr.yml +18 -0
  76. data/lib/paperclip/locales/gd.yml +20 -0
  77. data/lib/paperclip/logger.rb +21 -0
  78. data/lib/paperclip/matchers/have_attached_file_matcher.rb +54 -0
  79. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +101 -0
  80. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +59 -0
  81. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +97 -0
  82. data/lib/paperclip/matchers.rb +64 -0
  83. data/lib/paperclip/media_type_spoof_detector.rb +93 -0
  84. data/lib/paperclip/missing_attachment_styles.rb +84 -0
  85. data/lib/paperclip/processor.rb +56 -0
  86. data/lib/paperclip/processor_helpers.rb +52 -0
  87. data/lib/paperclip/rails_environment.rb +21 -0
  88. data/lib/paperclip/railtie.rb +31 -0
  89. data/lib/paperclip/schema.rb +104 -0
  90. data/lib/paperclip/storage/filesystem.rb +99 -0
  91. data/lib/paperclip/storage/fog.rb +262 -0
  92. data/lib/paperclip/storage/s3.rb +497 -0
  93. data/lib/paperclip/storage.rb +3 -0
  94. data/lib/paperclip/style.rb +106 -0
  95. data/lib/paperclip/tempfile.rb +42 -0
  96. data/lib/paperclip/tempfile_factory.rb +22 -0
  97. data/lib/paperclip/thumbnail.rb +131 -0
  98. data/lib/paperclip/url_generator.rb +83 -0
  99. data/lib/paperclip/validators/attachment_content_type_validator.rb +95 -0
  100. data/lib/paperclip/validators/attachment_file_name_validator.rb +82 -0
  101. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +28 -0
  102. data/lib/paperclip/validators/attachment_presence_validator.rb +28 -0
  103. data/lib/paperclip/validators/attachment_size_validator.rb +126 -0
  104. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +29 -0
  105. data/lib/paperclip/validators.rb +73 -0
  106. data/lib/paperclip/version.rb +3 -0
  107. data/lib/paperclip.rb +215 -0
  108. data/lib/tasks/paperclip.rake +140 -0
  109. data/paperclip.gemspec +51 -0
  110. data/shoulda_macros/paperclip.rb +134 -0
  111. data/spec/database.yml +4 -0
  112. data/spec/paperclip/attachment_definitions_spec.rb +13 -0
  113. data/spec/paperclip/attachment_processing_spec.rb +79 -0
  114. data/spec/paperclip/attachment_registry_spec.rb +158 -0
  115. data/spec/paperclip/attachment_spec.rb +1617 -0
  116. data/spec/paperclip/content_type_detector_spec.rb +58 -0
  117. data/spec/paperclip/file_command_content_type_detector_spec.rb +40 -0
  118. data/spec/paperclip/filename_cleaner_spec.rb +13 -0
  119. data/spec/paperclip/geometry_detector_spec.rb +47 -0
  120. data/spec/paperclip/geometry_parser_spec.rb +73 -0
  121. data/spec/paperclip/geometry_spec.rb +267 -0
  122. data/spec/paperclip/glue_spec.rb +63 -0
  123. data/spec/paperclip/has_attached_file_spec.rb +78 -0
  124. data/spec/paperclip/integration_spec.rb +702 -0
  125. data/spec/paperclip/interpolations_spec.rb +270 -0
  126. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +160 -0
  127. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +167 -0
  128. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +88 -0
  129. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
  130. data/spec/paperclip/io_adapters/file_adapter_spec.rb +134 -0
  131. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +142 -0
  132. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
  133. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +25 -0
  134. data/spec/paperclip/io_adapters/registry_spec.rb +35 -0
  135. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +64 -0
  136. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +146 -0
  137. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +231 -0
  138. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
  139. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +108 -0
  140. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
  141. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
  142. data/spec/paperclip/media_type_spoof_detector_spec.rb +126 -0
  143. data/spec/paperclip/meta_class_spec.rb +30 -0
  144. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +88 -0
  145. data/spec/paperclip/paperclip_spec.rb +196 -0
  146. data/spec/paperclip/plural_cache_spec.rb +37 -0
  147. data/spec/paperclip/processor_helpers_spec.rb +57 -0
  148. data/spec/paperclip/processor_spec.rb +26 -0
  149. data/spec/paperclip/rails_environment_spec.rb +30 -0
  150. data/spec/paperclip/rake_spec.rb +103 -0
  151. data/spec/paperclip/schema_spec.rb +298 -0
  152. data/spec/paperclip/storage/filesystem_spec.rb +102 -0
  153. data/spec/paperclip/storage/fog_spec.rb +606 -0
  154. data/spec/paperclip/storage/s3_live_spec.rb +188 -0
  155. data/spec/paperclip/storage/s3_spec.rb +1974 -0
  156. data/spec/paperclip/style_spec.rb +251 -0
  157. data/spec/paperclip/tempfile_factory_spec.rb +33 -0
  158. data/spec/paperclip/tempfile_spec.rb +35 -0
  159. data/spec/paperclip/thumbnail_spec.rb +504 -0
  160. data/spec/paperclip/url_generator_spec.rb +231 -0
  161. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +410 -0
  162. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +249 -0
  163. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +85 -0
  164. data/spec/paperclip/validators/attachment_size_validator_spec.rb +325 -0
  165. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +48 -0
  166. data/spec/paperclip/validators_spec.rb +179 -0
  167. data/spec/spec_helper.rb +52 -0
  168. data/spec/support/assertions.rb +84 -0
  169. data/spec/support/fake_model.rb +24 -0
  170. data/spec/support/fake_rails.rb +12 -0
  171. data/spec/support/fixtures/12k.png +0 -0
  172. data/spec/support/fixtures/50x50.png +0 -0
  173. data/spec/support/fixtures/5k.png +0 -0
  174. data/spec/support/fixtures/animated +0 -0
  175. data/spec/support/fixtures/animated.gif +0 -0
  176. data/spec/support/fixtures/animated.unknown +0 -0
  177. data/spec/support/fixtures/aws_s3.yml +13 -0
  178. data/spec/support/fixtures/bad.png +1 -0
  179. data/spec/support/fixtures/empty.html +1 -0
  180. data/spec/support/fixtures/empty.xlsx +0 -0
  181. data/spec/support/fixtures/fog.yml +8 -0
  182. data/spec/support/fixtures/rotated.jpg +0 -0
  183. data/spec/support/fixtures/s3.yml +8 -0
  184. data/spec/support/fixtures/sample.xlsm +0 -0
  185. data/spec/support/fixtures/spaced file.jpg +0 -0
  186. data/spec/support/fixtures/spaced file.png +0 -0
  187. data/spec/support/fixtures/text.txt +1 -0
  188. data/spec/support/fixtures/twopage.pdf +0 -0
  189. data/spec/support/fixtures/uppercase.PNG +0 -0
  190. data/spec/support/matchers/accept.rb +5 -0
  191. data/spec/support/matchers/exist.rb +5 -0
  192. data/spec/support/matchers/have_column.rb +23 -0
  193. data/spec/support/mock_attachment.rb +24 -0
  194. data/spec/support/mock_interpolator.rb +24 -0
  195. data/spec/support/mock_url_generator_builder.rb +26 -0
  196. data/spec/support/model_reconstruction.rb +72 -0
  197. data/spec/support/reporting.rb +11 -0
  198. data/spec/support/test_data.rb +13 -0
  199. data/spec/support/version_helper.rb +9 -0
  200. metadata +702 -0
@@ -0,0 +1,298 @@
1
+ require "spec_helper"
2
+ require "paperclip/schema"
3
+ require "active_support/testing/deprecation"
4
+
5
+ describe Paperclip::Schema do
6
+ include ActiveSupport::Testing::Deprecation
7
+
8
+ before do
9
+ rebuild_class
10
+ end
11
+
12
+ after do
13
+ begin
14
+ ActiveRecord::Migration.drop_table :dummies
15
+ rescue StandardError
16
+ nil
17
+ end
18
+ end
19
+
20
+ # Helper to check datetime column (Rails 7+ uses datetime(6) precision by default)
21
+ def expect_datetime_column(columns, column_name)
22
+ datetime_column = columns.find { |col| col[0] == column_name }
23
+ expect(datetime_column).to be_present
24
+ expect(datetime_column[1]).to match(/^datetime/)
25
+ end
26
+
27
+ # Helper to enable deprecation warnings for testing
28
+ def with_deprecation_warnings_enabled
29
+ if ActiveSupport::Deprecation.respond_to?(:silenced=)
30
+ old_silenced = ActiveSupport::Deprecation.silenced
31
+ ActiveSupport::Deprecation.silenced = false
32
+ yield
33
+ ActiveSupport::Deprecation.silenced = old_silenced
34
+ elsif defined?(ActiveSupport.deprecator)
35
+ old_behavior = ActiveSupport.deprecator.behavior
36
+ ActiveSupport.deprecator.behavior = :stderr
37
+ yield
38
+ ActiveSupport.deprecator.behavior = old_behavior
39
+ else
40
+ yield
41
+ end
42
+ end
43
+
44
+ context "within table definition" do
45
+ context "using #has_attached_file" do
46
+ it "creates attachment columns" do
47
+ ActiveRecord::Migration.create_table :dummies, force: true do |t|
48
+ if ActiveSupport::Deprecation.respond_to?(:silence)
49
+ ActiveSupport::Deprecation.silence do
50
+ t.has_attached_file :avatar
51
+ end
52
+ elsif defined?(ActiveSupport.deprecator)
53
+ ActiveSupport.deprecator.silence do
54
+ t.has_attached_file :avatar
55
+ end
56
+ else
57
+ t.has_attached_file :avatar
58
+ end
59
+ end
60
+
61
+ columns = Dummy.columns.map { |column| [column.name, column.sql_type] }
62
+
63
+ expect(columns).to include(["avatar_file_name", "varchar"])
64
+ expect(columns).to include(["avatar_content_type", "varchar"])
65
+ expect(columns).to include(["avatar_file_size", "bigint"])
66
+ expect_datetime_column(columns, "avatar_updated_at")
67
+ end
68
+
69
+ it "displays deprecation warning" do
70
+ with_deprecation_warnings_enabled do
71
+ ActiveRecord::Migration.create_table :dummies, force: true do |t|
72
+ deprecator = defined?(ActiveSupport.deprecator) ? ActiveSupport.deprecator : ActiveSupport::Deprecation
73
+ assert_deprecated(nil, deprecator) do
74
+ t.has_attached_file :avatar
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ context "using #attachment" do
82
+ before do
83
+ ActiveRecord::Migration.create_table :dummies, force: true do |t|
84
+ t.attachment :avatar
85
+ end
86
+ end
87
+
88
+ it "creates attachment columns" do
89
+ columns = Dummy.columns.map { |column| [column.name, column.sql_type] }
90
+
91
+ expect(columns).to include(["avatar_file_name", "varchar"])
92
+ expect(columns).to include(["avatar_content_type", "varchar"])
93
+ expect(columns).to include(["avatar_file_size", "bigint"])
94
+ expect_datetime_column(columns, "avatar_updated_at")
95
+ end
96
+ end
97
+
98
+ context "using #attachment with options" do
99
+ before do
100
+ ActiveRecord::Migration.create_table :dummies, force: true do |t|
101
+ t.attachment :avatar, default: 1, file_name: { default: "default" }
102
+ end
103
+ end
104
+
105
+ it "sets defaults on columns" do
106
+ defaults_columns = ["avatar_file_name", "avatar_content_type", "avatar_file_size"]
107
+ columns = Dummy.columns.select { |e| defaults_columns.include? e.name }
108
+
109
+ expect(columns).to have_column("avatar_file_name").with_default("default")
110
+ expect(columns).to have_column("avatar_content_type").with_default("1")
111
+ expect(columns).to have_column("avatar_file_size").with_default(1)
112
+ end
113
+ end
114
+ end
115
+
116
+ context "within schema statement" do
117
+ before do
118
+ ActiveRecord::Migration.create_table :dummies, force: true
119
+ end
120
+
121
+ context "migrating up" do
122
+ context "with single attachment" do
123
+ before do
124
+ ActiveRecord::Migration.add_attachment :dummies, :avatar
125
+ end
126
+
127
+ it "creates attachment columns" do
128
+ columns = Dummy.columns.map { |column| [column.name, column.sql_type] }
129
+
130
+ expect(columns).to include(["avatar_file_name", "varchar"])
131
+ expect(columns).to include(["avatar_content_type", "varchar"])
132
+ expect(columns).to include(["avatar_file_size", "bigint"])
133
+ expect_datetime_column(columns, "avatar_updated_at")
134
+ end
135
+ end
136
+
137
+ context "with single attachment and options" do
138
+ before do
139
+ ActiveRecord::Migration.add_attachment :dummies, :avatar, default: "1", file_name: { default: "default" }
140
+ end
141
+
142
+ it "sets defaults on columns" do
143
+ defaults_columns = ["avatar_file_name", "avatar_content_type", "avatar_file_size"]
144
+ columns = Dummy.columns.select { |e| defaults_columns.include? e.name }
145
+
146
+ expect(columns).to have_column("avatar_file_name").with_default("default")
147
+ expect(columns).to have_column("avatar_content_type").with_default("1")
148
+ expect(columns).to have_column("avatar_file_size").with_default(1)
149
+ end
150
+ end
151
+
152
+ context "with multiple attachments" do
153
+ before do
154
+ ActiveRecord::Migration.add_attachment :dummies, :avatar, :photo
155
+ end
156
+
157
+ it "creates attachment columns" do
158
+ columns = Dummy.columns.map { |column| [column.name, column.sql_type] }
159
+
160
+ expect(columns).to include(["avatar_file_name", "varchar"])
161
+ expect(columns).to include(["avatar_content_type", "varchar"])
162
+ expect(columns).to include(["avatar_file_size", "bigint"])
163
+ expect_datetime_column(columns, "avatar_updated_at")
164
+ expect(columns).to include(["photo_file_name", "varchar"])
165
+ expect(columns).to include(["photo_content_type", "varchar"])
166
+ expect(columns).to include(["photo_file_size", "bigint"])
167
+ expect_datetime_column(columns, "photo_updated_at")
168
+ end
169
+ end
170
+
171
+ context "with multiple attachments and options" do
172
+ before do
173
+ ActiveRecord::Migration.add_attachment :dummies, :avatar, :photo, default: "1", file_name: { default: "default" }
174
+ end
175
+
176
+ it "sets defaults on columns" do
177
+ defaults_columns = ["avatar_file_name", "avatar_content_type", "avatar_file_size", "photo_file_name", "photo_content_type", "photo_file_size"]
178
+ columns = Dummy.columns.select { |e| defaults_columns.include? e.name }
179
+
180
+ expect(columns).to have_column("avatar_file_name").with_default("default")
181
+ expect(columns).to have_column("avatar_content_type").with_default("1")
182
+ expect(columns).to have_column("avatar_file_size").with_default(1)
183
+ expect(columns).to have_column("photo_file_name").with_default("default")
184
+ expect(columns).to have_column("photo_content_type").with_default("1")
185
+ expect(columns).to have_column("photo_file_size").with_default(1)
186
+ end
187
+ end
188
+
189
+ context "with no attachment" do
190
+ it "raises an error" do
191
+ assert_raises ArgumentError do
192
+ ActiveRecord::Migration.add_attachment :dummies
193
+ end
194
+ end
195
+ end
196
+ end
197
+
198
+ context "migrating down" do
199
+ before do
200
+ ActiveRecord::Migration.change_table :dummies do |t|
201
+ t.column :avatar_file_name, :string
202
+ t.column :avatar_content_type, :string
203
+ t.column :avatar_file_size, :bigint
204
+ t.column :avatar_updated_at, :datetime
205
+ end
206
+ end
207
+
208
+ # Helper to check datetime column is NOT present
209
+ def expect_no_datetime_column(columns, column_name)
210
+ datetime_column = columns.find { |col| col[0] == column_name }
211
+ expect(datetime_column).to be_nil
212
+ end
213
+
214
+ context "using #drop_attached_file" do
215
+ it "removes the attachment columns" do
216
+ if ActiveSupport::Deprecation.respond_to?(:silence)
217
+ ActiveSupport::Deprecation.silence do
218
+ ActiveRecord::Migration.drop_attached_file :dummies, :avatar
219
+ end
220
+ elsif defined?(ActiveSupport.deprecator)
221
+ ActiveSupport.deprecator.silence do
222
+ ActiveRecord::Migration.drop_attached_file :dummies, :avatar
223
+ end
224
+ else
225
+ ActiveRecord::Migration.drop_attached_file :dummies, :avatar
226
+ end
227
+
228
+ columns = Dummy.columns.map { |column| [column.name, column.sql_type] }
229
+
230
+ expect(columns).to_not include(["avatar_file_name", "varchar"])
231
+ expect(columns).to_not include(["avatar_content_type", "varchar"])
232
+ expect(columns).to_not include(["avatar_file_size", "bigint"])
233
+ expect_no_datetime_column(columns, "avatar_updated_at")
234
+ end
235
+
236
+ it "displays a deprecation warning" do
237
+ with_deprecation_warnings_enabled do
238
+ deprecator = defined?(ActiveSupport.deprecator) ? ActiveSupport.deprecator : ActiveSupport::Deprecation
239
+ assert_deprecated(nil, deprecator) do
240
+ ActiveRecord::Migration.drop_attached_file :dummies, :avatar
241
+ end
242
+ end
243
+ end
244
+ end
245
+
246
+ context "using #remove_attachment" do
247
+ context "with single attachment" do
248
+ before do
249
+ ActiveRecord::Migration.remove_attachment :dummies, :avatar
250
+ end
251
+
252
+ it "removes the attachment columns" do
253
+ columns = Dummy.columns.map { |column| [column.name, column.sql_type] }
254
+
255
+ expect(columns).to_not include(["avatar_file_name", "varchar"])
256
+ expect(columns).to_not include(["avatar_content_type", "varchar"])
257
+ expect(columns).to_not include(["avatar_file_size", "bigint"])
258
+ expect_no_datetime_column(columns, "avatar_updated_at")
259
+ end
260
+ end
261
+
262
+ context "with multiple attachments" do
263
+ before do
264
+ ActiveRecord::Migration.change_table :dummies do |t|
265
+ t.column :photo_file_name, :string
266
+ t.column :photo_content_type, :string
267
+ t.column :photo_file_size, :bigint
268
+ t.column :photo_updated_at, :datetime
269
+ end
270
+
271
+ ActiveRecord::Migration.remove_attachment :dummies, :avatar, :photo
272
+ end
273
+
274
+ it "removes the attachment columns" do
275
+ columns = Dummy.columns.map { |column| [column.name, column.sql_type] }
276
+
277
+ expect(columns).to_not include(["avatar_file_name", "varchar"])
278
+ expect(columns).to_not include(["avatar_content_type", "varchar"])
279
+ expect(columns).to_not include(["avatar_file_size", "bigint"])
280
+ expect_no_datetime_column(columns, "avatar_updated_at")
281
+ expect(columns).to_not include(["photo_file_name", "varchar"])
282
+ expect(columns).to_not include(["photo_content_type", "varchar"])
283
+ expect(columns).to_not include(["photo_file_size", "bigint"])
284
+ expect_no_datetime_column(columns, "photo_updated_at")
285
+ end
286
+ end
287
+
288
+ context "with no attachment" do
289
+ it "raises an error" do
290
+ assert_raises ArgumentError do
291
+ ActiveRecord::Migration.remove_attachment :dummies
292
+ end
293
+ end
294
+ end
295
+ end
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,102 @@
1
+ require "spec_helper"
2
+
3
+ describe Paperclip::Storage::Filesystem do
4
+ context "Filesystem" do
5
+ context "normal file" do
6
+ before do
7
+ rebuild_model styles: { thumbnail: "25x25#" }
8
+ @dummy = Dummy.create!
9
+
10
+ @file = File.open(fixture_file("5k.png"))
11
+ @dummy.avatar = @file
12
+ end
13
+
14
+ after { @file.close }
15
+
16
+ it "allows file assignment" do
17
+ assert @dummy.save
18
+ end
19
+
20
+ it "stores the original" do
21
+ @dummy.save
22
+ assert_file_exists(@dummy.avatar.path)
23
+ end
24
+
25
+ it "stores the thumbnail" do
26
+ @dummy.save
27
+ assert_file_exists(@dummy.avatar.path(:thumbnail))
28
+ end
29
+
30
+ it "is rewinded after flush_writes" do
31
+ @dummy.avatar.instance_eval "def after_flush_writes; end"
32
+
33
+ files = @dummy.avatar.queued_for_write.values
34
+ @dummy.save
35
+ assert files.none?(&:eof?), "Expect all the files to be rewinded."
36
+ end
37
+
38
+ it "is removed after after_flush_writes" do
39
+ paths = @dummy.avatar.queued_for_write.values.map(&:path)
40
+ @dummy.save
41
+ assert paths.none? { |path| File.exist?(path) },
42
+ "Expect all the files to be deleted."
43
+ end
44
+
45
+ it "copies the file to a known location with copy_to_local_file" do
46
+ tempfile = Tempfile.new("known_location")
47
+ @dummy.avatar.copy_to_local_file(:original, tempfile.path)
48
+ tempfile.rewind
49
+ assert_equal @file.read, tempfile.read
50
+ tempfile.close
51
+ end
52
+
53
+ it "only issues a delete call once for each unique attachment style when nullifying attachment" do
54
+ @dummy.save
55
+ @dummy.avatar.clear(:thumbnail)
56
+ @dummy.avatar = nil
57
+ assert_equal 3, @dummy.avatar.queued_for_delete.size
58
+
59
+ expect(FileUtils).to receive(:rm).twice
60
+ @dummy.save
61
+
62
+ FileUtils.rm_rf("tmp")
63
+ end
64
+
65
+ it "only issues a delete call once for each unique attachment style when destroying model" do
66
+ @dummy.save
67
+ @dummy.avatar.clear(:thumbnail)
68
+ assert_equal 1, @dummy.avatar.queued_for_delete.size
69
+
70
+ expect(FileUtils).to receive(:rm).twice
71
+ @dummy.destroy
72
+
73
+ FileUtils.rm_rf("tmp")
74
+ end
75
+ end
76
+
77
+ context "with file that has space in file name" do
78
+ before do
79
+ rebuild_model styles: { thumbnail: "25x25#" }
80
+ @dummy = Dummy.create!
81
+
82
+ @file = File.open(fixture_file("spaced file.png"))
83
+ @dummy.avatar = @file
84
+ @dummy.save
85
+ end
86
+
87
+ after { @file.close }
88
+
89
+ it "stores the file" do
90
+ assert_file_exists(@dummy.avatar.path)
91
+ end
92
+
93
+ it "returns a replaced version for path" do
94
+ assert_match /.+\/spaced_file\.png/, @dummy.avatar.path
95
+ end
96
+
97
+ it "returns a replaced version for url" do
98
+ assert_match /.+\/spaced_file\.png/, @dummy.avatar.url
99
+ end
100
+ end
101
+ end
102
+ end