paperclip_jk 5.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (190) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +21 -0
  3. data/.hound.yml +1066 -0
  4. data/.rubocop.yml +1 -0
  5. data/.travis.yml +26 -0
  6. data/Appraisals +27 -0
  7. data/CONTRIBUTING.md +86 -0
  8. data/Gemfile +15 -0
  9. data/LICENSE +24 -0
  10. data/NEWS +424 -0
  11. data/README.md +999 -0
  12. data/RELEASING.md +17 -0
  13. data/Rakefile +44 -0
  14. data/UPGRADING +17 -0
  15. data/features/basic_integration.feature +81 -0
  16. data/features/migration.feature +70 -0
  17. data/features/rake_tasks.feature +62 -0
  18. data/features/step_definitions/attachment_steps.rb +110 -0
  19. data/features/step_definitions/html_steps.rb +15 -0
  20. data/features/step_definitions/rails_steps.rb +230 -0
  21. data/features/step_definitions/s3_steps.rb +14 -0
  22. data/features/step_definitions/web_steps.rb +107 -0
  23. data/features/support/env.rb +11 -0
  24. data/features/support/fakeweb.rb +13 -0
  25. data/features/support/file_helpers.rb +34 -0
  26. data/features/support/fixtures/boot_config.txt +15 -0
  27. data/features/support/fixtures/gemfile.txt +5 -0
  28. data/features/support/fixtures/preinitializer.txt +20 -0
  29. data/features/support/paths.rb +28 -0
  30. data/features/support/rails.rb +63 -0
  31. data/features/support/selectors.rb +19 -0
  32. data/gemfiles/4.2.awsv2.0.gemfile +17 -0
  33. data/gemfiles/4.2.awsv2.1.gemfile +17 -0
  34. data/gemfiles/4.2.awsv2.gemfile +20 -0
  35. data/gemfiles/5.0.awsv2.0.gemfile +17 -0
  36. data/gemfiles/5.0.awsv2.1.gemfile +17 -0
  37. data/gemfiles/5.0.awsv2.gemfile +25 -0
  38. data/lib/generators/paperclip/USAGE +8 -0
  39. data/lib/generators/paperclip/paperclip_generator.rb +30 -0
  40. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +15 -0
  41. data/lib/paperclip.rb +211 -0
  42. data/lib/paperclip/attachment.rb +610 -0
  43. data/lib/paperclip/attachment_registry.rb +60 -0
  44. data/lib/paperclip/callbacks.rb +42 -0
  45. data/lib/paperclip/content_type_detector.rb +80 -0
  46. data/lib/paperclip/errors.rb +34 -0
  47. data/lib/paperclip/file_command_content_type_detector.rb +30 -0
  48. data/lib/paperclip/filename_cleaner.rb +16 -0
  49. data/lib/paperclip/geometry.rb +158 -0
  50. data/lib/paperclip/geometry_detector_factory.rb +48 -0
  51. data/lib/paperclip/geometry_parser_factory.rb +31 -0
  52. data/lib/paperclip/glue.rb +17 -0
  53. data/lib/paperclip/has_attached_file.rb +115 -0
  54. data/lib/paperclip/helpers.rb +60 -0
  55. data/lib/paperclip/interpolations.rb +197 -0
  56. data/lib/paperclip/interpolations/plural_cache.rb +18 -0
  57. data/lib/paperclip/io_adapters/abstract_adapter.rb +47 -0
  58. data/lib/paperclip/io_adapters/attachment_adapter.rb +36 -0
  59. data/lib/paperclip/io_adapters/data_uri_adapter.rb +22 -0
  60. data/lib/paperclip/io_adapters/empty_string_adapter.rb +18 -0
  61. data/lib/paperclip/io_adapters/file_adapter.rb +22 -0
  62. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +15 -0
  63. data/lib/paperclip/io_adapters/identity_adapter.rb +12 -0
  64. data/lib/paperclip/io_adapters/nil_adapter.rb +34 -0
  65. data/lib/paperclip/io_adapters/registry.rb +32 -0
  66. data/lib/paperclip/io_adapters/stringio_adapter.rb +33 -0
  67. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +42 -0
  68. data/lib/paperclip/io_adapters/uri_adapter.rb +44 -0
  69. data/lib/paperclip/locales/en.yml +18 -0
  70. data/lib/paperclip/logger.rb +21 -0
  71. data/lib/paperclip/matchers.rb +64 -0
  72. data/lib/paperclip/matchers/have_attached_file_matcher.rb +54 -0
  73. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +100 -0
  74. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +59 -0
  75. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +96 -0
  76. data/lib/paperclip/media_type_spoof_detector.rb +89 -0
  77. data/lib/paperclip/missing_attachment_styles.rb +79 -0
  78. data/lib/paperclip/processor.rb +48 -0
  79. data/lib/paperclip/processor_helpers.rb +50 -0
  80. data/lib/paperclip/rails_environment.rb +25 -0
  81. data/lib/paperclip/railtie.rb +31 -0
  82. data/lib/paperclip/schema.rb +77 -0
  83. data/lib/paperclip/storage.rb +4 -0
  84. data/lib/paperclip/storage/database.rb +140 -0
  85. data/lib/paperclip/storage/filesystem.rb +90 -0
  86. data/lib/paperclip/storage/fog.rb +244 -0
  87. data/lib/paperclip/storage/s3.rb +442 -0
  88. data/lib/paperclip/style.rb +109 -0
  89. data/lib/paperclip/tempfile.rb +43 -0
  90. data/lib/paperclip/tempfile_factory.rb +23 -0
  91. data/lib/paperclip/thumbnail.rb +121 -0
  92. data/lib/paperclip/url_generator.rb +72 -0
  93. data/lib/paperclip/validators.rb +74 -0
  94. data/lib/paperclip/validators/attachment_content_type_validator.rb +88 -0
  95. data/lib/paperclip/validators/attachment_file_name_validator.rb +80 -0
  96. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +29 -0
  97. data/lib/paperclip/validators/attachment_presence_validator.rb +30 -0
  98. data/lib/paperclip/validators/attachment_size_validator.rb +109 -0
  99. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +27 -0
  100. data/lib/paperclip/version.rb +3 -0
  101. data/lib/tasks/paperclip.rake +127 -0
  102. data/paperclip.gemspec +54 -0
  103. data/shoulda_macros/paperclip.rb +134 -0
  104. data/spec/database.yml +4 -0
  105. data/spec/paperclip/attachment_definitions_spec.rb +13 -0
  106. data/spec/paperclip/attachment_processing_spec.rb +80 -0
  107. data/spec/paperclip/attachment_registry_spec.rb +158 -0
  108. data/spec/paperclip/attachment_spec.rb +1517 -0
  109. data/spec/paperclip/content_type_detector_spec.rb +48 -0
  110. data/spec/paperclip/file_command_content_type_detector_spec.rb +26 -0
  111. data/spec/paperclip/filename_cleaner_spec.rb +14 -0
  112. data/spec/paperclip/geometry_detector_spec.rb +39 -0
  113. data/spec/paperclip/geometry_parser_spec.rb +73 -0
  114. data/spec/paperclip/geometry_spec.rb +255 -0
  115. data/spec/paperclip/glue_spec.rb +44 -0
  116. data/spec/paperclip/has_attached_file_spec.rb +158 -0
  117. data/spec/paperclip/integration_spec.rb +668 -0
  118. data/spec/paperclip/interpolations_spec.rb +262 -0
  119. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +78 -0
  120. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +139 -0
  121. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +83 -0
  122. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
  123. data/spec/paperclip/io_adapters/file_adapter_spec.rb +131 -0
  124. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +113 -0
  125. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
  126. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +25 -0
  127. data/spec/paperclip/io_adapters/registry_spec.rb +35 -0
  128. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +64 -0
  129. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +146 -0
  130. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +102 -0
  131. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
  132. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +109 -0
  133. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
  134. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
  135. data/spec/paperclip/media_type_spoof_detector_spec.rb +70 -0
  136. data/spec/paperclip/meta_class_spec.rb +30 -0
  137. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +84 -0
  138. data/spec/paperclip/paperclip_spec.rb +192 -0
  139. data/spec/paperclip/plural_cache_spec.rb +37 -0
  140. data/spec/paperclip/processor_helpers_spec.rb +57 -0
  141. data/spec/paperclip/processor_spec.rb +26 -0
  142. data/spec/paperclip/rails_environment_spec.rb +33 -0
  143. data/spec/paperclip/rake_spec.rb +103 -0
  144. data/spec/paperclip/schema_spec.rb +248 -0
  145. data/spec/paperclip/storage/filesystem_spec.rb +79 -0
  146. data/spec/paperclip/storage/fog_spec.rb +545 -0
  147. data/spec/paperclip/storage/s3_live_spec.rb +186 -0
  148. data/spec/paperclip/storage/s3_spec.rb +1583 -0
  149. data/spec/paperclip/style_spec.rb +255 -0
  150. data/spec/paperclip/tempfile_factory_spec.rb +33 -0
  151. data/spec/paperclip/thumbnail_spec.rb +500 -0
  152. data/spec/paperclip/url_generator_spec.rb +211 -0
  153. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
  154. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +160 -0
  155. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +85 -0
  156. data/spec/paperclip/validators/attachment_size_validator_spec.rb +235 -0
  157. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +52 -0
  158. data/spec/paperclip/validators_spec.rb +164 -0
  159. data/spec/spec_helper.rb +45 -0
  160. data/spec/support/assertions.rb +78 -0
  161. data/spec/support/fake_model.rb +25 -0
  162. data/spec/support/fake_rails.rb +12 -0
  163. data/spec/support/fixtures/12k.png +0 -0
  164. data/spec/support/fixtures/50x50.png +0 -0
  165. data/spec/support/fixtures/5k.png +0 -0
  166. data/spec/support/fixtures/animated +0 -0
  167. data/spec/support/fixtures/animated.gif +0 -0
  168. data/spec/support/fixtures/animated.unknown +0 -0
  169. data/spec/support/fixtures/bad.png +1 -0
  170. data/spec/support/fixtures/empty.html +1 -0
  171. data/spec/support/fixtures/empty.xlsx +0 -0
  172. data/spec/support/fixtures/fog.yml +8 -0
  173. data/spec/support/fixtures/rotated.jpg +0 -0
  174. data/spec/support/fixtures/s3.yml +8 -0
  175. data/spec/support/fixtures/spaced file.jpg +0 -0
  176. data/spec/support/fixtures/spaced file.png +0 -0
  177. data/spec/support/fixtures/text.txt +1 -0
  178. data/spec/support/fixtures/twopage.pdf +0 -0
  179. data/spec/support/fixtures/uppercase.PNG +0 -0
  180. data/spec/support/matchers/accept.rb +5 -0
  181. data/spec/support/matchers/exist.rb +5 -0
  182. data/spec/support/matchers/have_column.rb +23 -0
  183. data/spec/support/mock_attachment.rb +22 -0
  184. data/spec/support/mock_interpolator.rb +24 -0
  185. data/spec/support/mock_url_generator_builder.rb +27 -0
  186. data/spec/support/model_reconstruction.rb +68 -0
  187. data/spec/support/reporting.rb +11 -0
  188. data/spec/support/test_data.rb +13 -0
  189. data/spec/support/version_helper.rb +9 -0
  190. metadata +713 -0
@@ -0,0 +1,999 @@
1
+ Paperclip
2
+ =========
3
+
4
+ ## Documentation valid for `master` branch
5
+
6
+ Please check the documentation for the paperclip version you are using:
7
+ https://github.com/thoughtbot/paperclip/releases
8
+
9
+ ---
10
+
11
+ [![Build Status](https://secure.travis-ci.org/thoughtbot/paperclip.svg?branch=master)](http://travis-ci.org/thoughtbot/paperclip)
12
+ [![Dependency Status](https://gemnasium.com/thoughtbot/paperclip.svg?travis)](https://gemnasium.com/thoughtbot/paperclip)
13
+ [![Code Climate](https://codeclimate.com/github/thoughtbot/paperclip.svg)](https://codeclimate.com/github/thoughtbot/paperclip)
14
+ [![Inline docs](http://inch-ci.org/github/thoughtbot/paperclip.svg)](http://inch-ci.org/github/thoughtbot/paperclip)
15
+ [![Security](https://hakiri.io/github/thoughtbot/paperclip/master.svg)](https://hakiri.io/github/thoughtbot/paperclip/master)
16
+
17
+ <!-- START doctoc generated TOC please keep comment here to allow auto update -->
18
+ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
19
+
20
+
21
+ - [Requirements](#requirements)
22
+ - [Ruby and Rails](#ruby-and-rails)
23
+ - [Image Processor](#image-processor)
24
+ - [`file`](#file)
25
+ - [Installation](#installation)
26
+ - [Quick Start](#quick-start)
27
+ - [Models](#models)
28
+ - [Migrations](#migrations)
29
+ - [Edit and New Views](#edit-and-new-views)
30
+ - [Edit and New Views with Simple Form](#edit-and-new-views-with-simple-form)
31
+ - [Controller](#controller)
32
+ - [View Helpers](#view-helpers)
33
+ - [Deleting an Attachment](#deleting-an-attachment)
34
+ - [Usage](#usage)
35
+ - [Validations](#validations)
36
+ - [Internationalization (I18n)](#internationalization-i18n)
37
+ - [Security Validations](#security-validations)
38
+ - [Defaults](#defaults)
39
+ - [Migrations](#migrations-1)
40
+ - [Add Attachment Column To A Table](#add-attachment-column-to-a-table)
41
+ - [Schema Definition](#schema-definition)
42
+ - [Vintage syntax](#vintage-syntax)
43
+ - [Storage](#storage)
44
+ - [Understanding Storage](#understanding-storage)
45
+ - [Post Processing](#post-processing)
46
+ - [Events](#events)
47
+ - [URI Obfuscation](#uri-obfuscation)
48
+ - [MD5 Checksum / Fingerprint](#md5-checksum--fingerprint)
49
+ - [File Preservation for Soft-Delete](#file-preservation-for-soft-delete)
50
+ - [Custom Attachment Processors](#custom-attachment-processors)
51
+ - [Dynamic Configuration](#dynamic-configuration)
52
+ - [Dynamic Styles:](#dynamic-styles)
53
+ - [Dynamic Processors:](#dynamic-processors)
54
+ - [Logging](#logging)
55
+ - [Deployment](#deployment)
56
+ - [Attachment Styles](#attachment-styles)
57
+ - [Testing](#testing)
58
+ - [Contributing](#contributing)
59
+ - [License](#license)
60
+ - [About thoughtbot](#about-thoughtbot)
61
+
62
+ <!-- END doctoc generated TOC please keep comment here to allow auto update -->
63
+
64
+ Paperclip is intended as an easy file attachment library for ActiveRecord. The
65
+ intent behind it was to keep setup as easy as possible and to treat files as
66
+ much like other attributes as possible. This means they aren't saved to their
67
+ final locations on disk, nor are they deleted if set to nil, until
68
+ ActiveRecord::Base#save is called. It manages validations based on size and
69
+ presence, if required. It can transform its assigned image into thumbnails if
70
+ needed, and the prerequisites are as simple as installing ImageMagick (which,
71
+ for most modern Unix-based systems, is as easy as installing the right
72
+ packages). Attached files are saved to the filesystem and referenced in the
73
+ browser by an easily understandable specification, which has sensible and
74
+ useful defaults.
75
+
76
+ See the documentation for `has_attached_file` in [`Paperclip::ClassMethods`](http://www.rubydoc.info/gems/paperclip/Paperclip/ClassMethods) for
77
+ more detailed options.
78
+
79
+ The complete [RDoc](http://www.rubydoc.info/gems/paperclip) is online.
80
+
81
+ ---
82
+
83
+ Requirements
84
+ ------------
85
+
86
+ ### Ruby and Rails
87
+
88
+ Paperclip now requires Ruby version **>= 2.1** and Rails version **>= 4.2**
89
+ (only if you're going to use Paperclip with Ruby on Rails.)
90
+
91
+ ### Image Processor
92
+
93
+ [ImageMagick](http://www.imagemagick.org) must be installed and Paperclip must have access to it. To ensure
94
+ that it does, on your command line, run `which convert` (one of the ImageMagick
95
+ utilities). This will give you the path where that utility is installed. For
96
+ example, it might return `/usr/local/bin/convert`.
97
+
98
+ Then, in your environment config file, let Paperclip know to look there by adding that
99
+ directory to its path.
100
+
101
+ In development mode, you might add this line to `config/environments/development.rb)`:
102
+
103
+ ```ruby
104
+ Paperclip.options[:command_path] = "/usr/local/bin/"
105
+ ```
106
+
107
+ If you're on Mac OS X, you'll want to run the following with [Homebrew] (http://www.brew.sh):
108
+
109
+ brew install imagemagick
110
+
111
+ If you are dealing with pdf uploads or running the test suite, you'll also need
112
+ to install GhostScript. On Mac OS X, you can also install that using Homebrew:
113
+
114
+ brew install gs
115
+
116
+ If you are on Ubuntu (or any Debian base Linux distribution), you'll want to run
117
+ the following with apt-get:
118
+
119
+ sudo apt-get install imagemagick -y
120
+
121
+ ### `file`
122
+
123
+ The Unix [`file` command](https://en.wikipedia.org/wiki/File_(command)) is required for content-type checking.
124
+ This utility isn't available in Windows, but comes bundled with Ruby [Devkit](https://github.com/oneclick/rubyinstaller/wiki/Development-Kit),
125
+ so Windows users must make sure that the devkit is installed and added to the system `PATH`.
126
+
127
+ **Manual Installation**
128
+
129
+ If you're using Windows 7+ as a development environment, you may need to install the `file.exe` application manually. The `file spoofing` system in Paperclip 4+ relies on this; if you don't have it working, you'll receive `Validation failed: Upload file has an extension that does not match its contents.` errors.
130
+
131
+ To manually install, you should perform the following:
132
+
133
+ > **Download & install `file` from [this URL](http://gnuwin32.sourceforge.net/packages/file.htm)**
134
+
135
+ To test, you can use the image below:
136
+ ![untitled](https://cloud.githubusercontent.com/assets/1104431/4524452/a1f8cce4-4d44-11e4-872e-17adb96f79c9.png)
137
+
138
+ Next, you need to integrate with your environment - preferably through the `PATH` variable, or by changing your `config/environments/development.rb` file
139
+
140
+ **PATH**
141
+
142
+ 1. Click "Start"
143
+ 2. On "Computer", right-click and select "Properties"
144
+ 3. In Properties, select "Advanced System Settings"
145
+ 4. Click the "Environment Variables" button
146
+ 5. Locate the "PATH" var - at the end, add the path to your newly installed `file.exe` (typically `C:\Program Files (x86)\GnuWin32\bin`)
147
+ 6. Restart any CMD shells you have open & see if it works
148
+
149
+ OR
150
+
151
+ **Environment**
152
+
153
+ 1. Open `config/environments/development.rb`
154
+ 2. Add the following line: `Paperclip.options[:command_path] = 'C:\Program Files (x86)\GnuWin32\bin'`
155
+ 3. Restart your Rails server
156
+
157
+ Either of these methods will give your Rails setup access to the `file.exe` functionality, thus providing the ability to check the contents of a file (fixing the spoofing problem)
158
+
159
+ ---
160
+
161
+ Installation
162
+ ------------
163
+
164
+ Paperclip is distributed as a gem, which is how it should be used in your app.
165
+
166
+ Include the gem in your Gemfile:
167
+
168
+ ```ruby
169
+ gem "paperclip", "~> 5.0.0.beta1"
170
+ ```
171
+
172
+ Or, if you want to get the latest, you can get master from the main paperclip repository:
173
+
174
+ ```ruby
175
+ gem "paperclip", git: "git://github.com/thoughtbot/paperclip.git"
176
+ ```
177
+
178
+ If you're trying to use features that don't seem to be in the latest released gem, but are
179
+ mentioned in this README, then you probably need to specify the master branch if you want to
180
+ use them. This README is probably ahead of the latest released version if you're reading it
181
+ on GitHub.
182
+
183
+ For Non-Rails usage:
184
+
185
+ ```ruby
186
+ class ModuleName < ActiveRecord::Base
187
+ include Paperclip::Glue
188
+ ...
189
+ end
190
+ ```
191
+
192
+ ---
193
+
194
+ Quick Start
195
+ -----------
196
+
197
+ ### Models
198
+
199
+ ```ruby
200
+ class User < ActiveRecord::Base
201
+ has_attached_file :avatar, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
202
+ validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\Z/
203
+ end
204
+ ```
205
+
206
+ ### Migrations
207
+
208
+ ```ruby
209
+ class AddAvatarColumnsToUsers < ActiveRecord::Migration
210
+ def up
211
+ add_attachment :users, :avatar
212
+ end
213
+
214
+ def down
215
+ remove_attachment :users, :avatar
216
+ end
217
+ end
218
+ ```
219
+
220
+ (Or you can use the Rails migration generator: `rails generate paperclip user avatar`)
221
+
222
+ ### Edit and New Views
223
+
224
+ ```erb
225
+ <%= form_for @user, url: users_path, html: { multipart: true } do |form| %>
226
+ <%= form.file_field :avatar %>
227
+ <% end %>
228
+ ```
229
+
230
+ ### Edit and New Views with [Simple Form](https://github.com/plataformatec/simple_form)
231
+
232
+ ```erb
233
+ <%= simple_form_for @user, url: users_path do |form| %>
234
+ <%= form.input :avatar, as: :file %>
235
+ <% end %>
236
+ ```
237
+
238
+ ### Controller
239
+
240
+ ```ruby
241
+ def create
242
+ @user = User.create( user_params )
243
+ end
244
+
245
+ private
246
+
247
+ # Use strong_parameters for attribute whitelisting
248
+ # Be sure to update your create() and update() controller methods.
249
+
250
+ def user_params
251
+ params.require(:user).permit(:avatar)
252
+ end
253
+ ```
254
+
255
+ ### View Helpers
256
+
257
+ ```erb
258
+ <%= image_tag @user.avatar.url %>
259
+ <%= image_tag @user.avatar.url(:medium) %>
260
+ <%= image_tag @user.avatar.url(:thumb) %>
261
+ ```
262
+
263
+ ### Deleting an Attachment
264
+
265
+ Set the attribute to `nil` and save.
266
+
267
+ ```ruby
268
+ @user.avatar = nil
269
+ @user.save
270
+ ```
271
+ ---
272
+
273
+ Usage
274
+ -----
275
+
276
+ The basics of Paperclip are quite simple: Declare that your model has an
277
+ attachment with the `has_attached_file` method, and give it a name.
278
+
279
+ Paperclip will wrap up to four attributes (all prefixed with that attachment's name,
280
+ so you can have multiple attachments per model if you wish) and give them a
281
+ friendly front end. These attributes are:
282
+
283
+ * `<attachment>_file_name`
284
+ * `<attachment>_file_size`
285
+ * `<attachment>_content_type`
286
+ * `<attachment>_updated_at`
287
+
288
+ By default, only `<attachment>_file_name` is required for Paperclip to operate.
289
+ You'll need to add `<attachment>_content_type` in case you want to use content type
290
+ validation.
291
+
292
+ More information about the options passed to `has_attached_file` is available in the
293
+ documentation of [`Paperclip::ClassMethods`](http://www.rubydoc.info/gems/paperclip/Paperclip/ClassMethods).
294
+
295
+ Validations
296
+ -----------
297
+
298
+ For validations, Paperclip introduces several validators to validate your attachment:
299
+
300
+ * `AttachmentContentTypeValidator`
301
+ * `AttachmentPresenceValidator`
302
+ * `AttachmentSizeValidator`
303
+
304
+ Example Usage:
305
+
306
+ ```ruby
307
+ validates :avatar, attachment_presence: true
308
+ validates_with AttachmentPresenceValidator, attributes: :avatar
309
+ validates_with AttachmentSizeValidator, attributes: :avatar, less_than: 1.megabytes
310
+
311
+ ```
312
+
313
+ Validators can also be defined using the old helper style:
314
+
315
+ * `validates_attachment_presence`
316
+ * `validates_attachment_content_type`
317
+ * `validates_attachment_size`
318
+
319
+ Example Usage:
320
+
321
+ ```ruby
322
+ validates_attachment_presence :avatar
323
+ ```
324
+
325
+ Lastly, you can also define multiple validations on a single attachment using `validates_attachment`:
326
+
327
+ ```ruby
328
+ validates_attachment :avatar, presence: true,
329
+ content_type: { content_type: "image/jpeg" },
330
+ size: { in: 0..10.kilobytes }
331
+ ```
332
+
333
+ _NOTE: Post-processing will not even **start** if the attachment is not valid
334
+ according to the validations. Your callbacks and processors will **only** be
335
+ called with valid attachments._
336
+
337
+ ```ruby
338
+ class Message < ActiveRecord::Base
339
+ has_attached_file :asset, styles: {thumb: "100x100#"}
340
+
341
+ before_post_process :skip_for_audio
342
+
343
+ def skip_for_audio
344
+ ! %w(audio/ogg application/ogg).include?(asset_content_type)
345
+ end
346
+ end
347
+ ```
348
+
349
+ If you have other validations that depend on assignment order, the recommended
350
+ course of action is to prevent the assignment of the attachment until
351
+ afterwards, then assign manually:
352
+
353
+ ```ruby
354
+ class Book < ActiveRecord::Base
355
+ has_attached_file :document, styles: {thumbnail: "60x60#"}
356
+ validates_attachment :document, content_type: { content_type: "application/pdf" }
357
+ validates_something_else # Other validations that conflict with Paperclip's
358
+ end
359
+
360
+ class BooksController < ApplicationController
361
+ def create
362
+ @book = Book.new(book_params)
363
+ @book.document = params[:book][:document]
364
+ @book.save
365
+ respond_with @book
366
+ end
367
+
368
+ private
369
+
370
+ def book_params
371
+ params.require(:book).permit(:title, :author)
372
+ end
373
+ end
374
+ ```
375
+
376
+ **A note on content_type validations and security**
377
+
378
+ You should ensure that you validate files to be only those MIME types you
379
+ explicitly want to support. If you don't, you could be open to
380
+ <a href="https://www.owasp.org/index.php/Testing_for_Stored_Cross_site_scripting_(OWASP-DV-002)">XSS attacks</a>
381
+ if a user uploads a file with a malicious HTML payload.
382
+
383
+ If you're only interested in images, restrict your allowed content_types to
384
+ image-y ones:
385
+
386
+ ```ruby
387
+ validates_attachment :avatar,
388
+ content_type: { content_type: ["image/jpeg", "image/gif", "image/png"] }
389
+ ```
390
+
391
+ `Paperclip::ContentTypeDetector` will attempt to match a file's extension to an
392
+ inferred content_type, regardless of the actual contents of the file.
393
+
394
+ ---
395
+
396
+ Internationalization (I18n)
397
+ ---------------------------
398
+
399
+ For using or adding locale files in different languages, check the project
400
+ https://github.com/thoughtbot/paperclip-i18n.
401
+
402
+ Security Validations
403
+ ====================
404
+
405
+ Thanks to a report from [Egor Homakov](http://homakov.blogspot.com/) we have
406
+ taken steps to prevent people from spoofing Content-Types and getting data
407
+ you weren't expecting onto your server.
408
+
409
+ NOTE: Starting at version 4.0.0, all attachments are *required* to include a
410
+ content_type validation, a file_name validation, or to explicitly state that
411
+ they're not going to have either. *Paperclip will raise an error* if you do not
412
+ do this.
413
+
414
+ ```ruby
415
+ class ActiveRecord::Base
416
+ has_attached_file :avatar
417
+ # Validate content type
418
+ validates_attachment_content_type :avatar, content_type: /\Aimage/
419
+ # Validate filename
420
+ validates_attachment_file_name :avatar, matches: [/png\Z/, /jpe?g\Z/]
421
+ # Explicitly do not validate
422
+ do_not_validate_attachment_file_type :avatar
423
+ end
424
+ ```
425
+
426
+ This keeps Paperclip secure-by-default, and will prevent people trying to mess
427
+ with your filesystem.
428
+
429
+ NOTE: Also starting at version 4.0.0, Paperclip has another validation that
430
+ cannot be turned off. This validation will prevent content type spoofing. That
431
+ is, uploading a PHP document (for example) as part of the EXIF tags of a
432
+ well-formed JPEG. This check is limited to the media type (the first part of the
433
+ MIME type, so, 'text' in `text/plain`). This will prevent HTML documents from
434
+ being uploaded as JPEGs, but will not prevent GIFs from being uploaded with a
435
+ `.jpg` extension. This validation will only add validation errors to the form. It
436
+ will not cause errors to be raised.
437
+
438
+ This can sometimes cause false validation errors in applications that use custom
439
+ file extensions. In these cases you may wish to add your custom extension to the
440
+ list of content type mappings by creating `config/initializers/paperclip.rb`:
441
+
442
+ ```ruby
443
+ # Allow ".foo" as an extension for files with the MIME type "text/plain".
444
+ Paperclip.options[:content_type_mappings] = {
445
+ foo: %w(text/plain)
446
+ }
447
+ ```
448
+
449
+ ---
450
+
451
+ Defaults
452
+ --------
453
+ Global defaults for all your Paperclip attachments can be defined by changing the Paperclip::Attachment.default_options Hash. This can be useful for setting your default storage settings per example so you won't have to define them in every `has_attached_file` definition.
454
+
455
+ If you're using Rails, you can define a Hash with default options in `config/application.rb` or in any of the `config/environments/*.rb` files on config.paperclip_defaults. These will get merged into `Paperclip::Attachment.default_options` as your Rails app boots. An example:
456
+
457
+ ```ruby
458
+ module YourApp
459
+ class Application < Rails::Application
460
+ # Other code...
461
+
462
+ config.paperclip_defaults = { storage: :fog, fog_credentials: { provider: "Local", local_root: "#{Rails.root}/public"}, fog_directory: "", fog_host: "localhost"}
463
+ end
464
+ end
465
+ ```
466
+
467
+ Another option is to directly modify the `Paperclip::Attachment.default_options` Hash - this method works for non-Rails applications or is an option if you prefer to place the Paperclip default settings in an initializer.
468
+
469
+ An example Rails initializer would look something like this:
470
+
471
+ ```ruby
472
+ Paperclip::Attachment.default_options[:storage] = :fog
473
+ Paperclip::Attachment.default_options[:fog_credentials] = { provider: "Local", local_root: "#{Rails.root}/public"}
474
+ Paperclip::Attachment.default_options[:fog_directory] = ""
475
+ Paperclip::Attachment.default_options[:fog_host] = "http://localhost:3000"
476
+ ```
477
+ ---
478
+
479
+ Migrations
480
+ ----------
481
+
482
+ Paperclip defines several migration methods which can be used to create the necessary columns in your
483
+ model. There are two types of helper methods to aid in this, as follows:
484
+
485
+ ### Add Attachment Column To A Table
486
+
487
+ The `attachment` helper can be used when creating a table:
488
+
489
+ ```ruby
490
+ class CreateUsersWithAttachments < ActiveRecord::Migration
491
+ def up
492
+ create_table :users do |t|
493
+ t.attachment :avatar
494
+ end
495
+ end
496
+
497
+ # This is assuming you are only using the users table for Paperclip attachment. Drop with care!
498
+ def down
499
+ drop_table :users
500
+ end
501
+ end
502
+ ```
503
+
504
+ You can also use the `change` method, instead of the `up`/`down` combination above, as shown below:
505
+
506
+ ```ruby
507
+ class CreateUsersWithAttachments < ActiveRecord::Migration
508
+ def change
509
+ create_table :users do |t|
510
+ t.attachment :avatar
511
+ end
512
+ end
513
+ end
514
+ ```
515
+
516
+ ### Schema Definition
517
+
518
+ Alternatively, the `add_attachment` and `remove_attachment` methods can be used to add new Paperclip columns to an existing table:
519
+
520
+ ```ruby
521
+ class AddAttachmentColumnsToUsers < ActiveRecord::Migration
522
+ def up
523
+ add_attachment :users, :avatar
524
+ end
525
+
526
+ def down
527
+ remove_attachment :users, :avatar
528
+ end
529
+ end
530
+ ```
531
+
532
+ Or you can do this with the `change` method:
533
+
534
+ ```ruby
535
+ class AddAttachmentColumnsToUsers < ActiveRecord::Migration
536
+ def change
537
+ add_attachment :users, :avatar
538
+ end
539
+ end
540
+ ```
541
+
542
+ ### Vintage syntax
543
+
544
+ Vintage syntax (such as `t.has_attached_file` and `drop_attached_file`) is still supported in
545
+ Paperclip 3.x, but you're advised to update those migration files to use this new syntax.
546
+
547
+ ---
548
+
549
+ Storage
550
+ -------
551
+
552
+ Paperclip ships with 3 storage adapters:
553
+
554
+ * File Storage
555
+ * S3 Storage (via `aws-sdk`)
556
+ * Fog Storage
557
+
558
+ If you would like to use Paperclip with another storage, you can install these
559
+ gems along side with Paperclip:
560
+
561
+ * [paperclip-azure-storage](https://github.com/gmontard/paperclip-azure-storage)
562
+ * [paperclip-dropbox](https://github.com/janko-m/paperclip-dropbox)
563
+
564
+ ### Understanding Storage
565
+
566
+ The files that are assigned as attachments are, by default, placed in the
567
+ directory specified by the `:path` option to `has_attached_file`. By default, this
568
+ location is `:rails_root/public/system/:class/:attachment/:id_partition/:style/:filename`.
569
+ This location was chosen because, on standard Capistrano deployments, the
570
+ `public/system` directory can be symlinked to the app's shared directory, meaning it
571
+ survives between deployments. For example, using that `:path`, you may have a
572
+ file at
573
+
574
+ /data/myapp/releases/20081229172410/public/system/users/avatar/000/000/013/small/my_pic.png
575
+
576
+ _**NOTE**: This is a change from previous versions of Paperclip, but is overall a
577
+ safer choice for the default file store._
578
+
579
+ You may also choose to store your files using Amazon's S3 service. To do so, include
580
+ the `aws-sdk` gem in your Gemfile:
581
+
582
+ ```ruby
583
+ gem 'aws-sdk', '>= 2.0.34'
584
+ ```
585
+
586
+ And then you can specify using S3 from `has_attached_file`.
587
+ You can find more information about configuring and using S3 storage in
588
+ [the `Paperclip::Storage::S3` documentation](http://www.rubydoc.info/gems/paperclip/Paperclip/Storage/S3).
589
+
590
+ Files on the local filesystem (and in the Rails app's public directory) will be
591
+ available to the internet at large. If you require access control, it's
592
+ possible to place your files in a different location. You will need to change
593
+ both the `:path` and `:url` options in order to make sure the files are unavailable
594
+ to the public. Both `:path` and `:url` allow the same set of interpolated
595
+ variables.
596
+
597
+ ---
598
+
599
+ Post Processing
600
+ ---------------
601
+
602
+ Paperclip supports an extensible selection of post-processors. When you define
603
+ a set of styles for an attachment, by default it is expected that those
604
+ "styles" are actually "thumbnails." However, you can do much more than just
605
+ thumbnail images. By defining a subclass of Paperclip::Processor, you can
606
+ perform any processing you want on the files that are attached. Any file in
607
+ your Rails app's `lib/paperclip` and `lib/paperclip_processors` directories is
608
+ automatically loaded by Paperclip, allowing you to easily define custom
609
+ processors. You can specify a processor with the `:processors` option to
610
+ `has_attached_file`:
611
+
612
+ ```ruby
613
+ has_attached_file :scan, styles: { text: { quality: :better } },
614
+ processors: [:ocr]
615
+ ```
616
+
617
+ This would load the hypothetical class Paperclip::Ocr, which would have the
618
+ hash "{ quality: :better }" passed to it along with the uploaded file. For
619
+ more information about defining processors, see
620
+ [Paperclip::Processor](https://github.com/thoughtbot/paperclip/blob/master/lib/paperclip/processor.rb).
621
+
622
+ The default processor is Paperclip::Thumbnail. For backward compatibility
623
+ reasons, you can pass a single geometry string or an array containing a
624
+ geometry and a format that the file will be converted to, like so:
625
+
626
+ ```ruby
627
+ has_attached_file :avatar, styles: { thumb: ["32x32#", :png] }
628
+ ```
629
+
630
+ This will convert the "thumb" style to a 32x32 square in PNG format, regardless
631
+ of what was uploaded. If the format is not specified, it is kept the same (i.e.
632
+ JPGs will remain JPGs). For more information on the accepted style formats, see
633
+ [here](http://www.imagemagick.org/script/command-line-processing.php#geometry).
634
+
635
+ Multiple processors can be specified, and they will be invoked in the order
636
+ they are defined in the `:processors` array. Each successive processor will
637
+ be given the result of the previous processor's execution. All processors will
638
+ receive the same parameters, which are defined in the `:styles` hash.
639
+ For example, assuming we had this definition:
640
+
641
+ ```ruby
642
+ has_attached_file :scan, styles: { text: { quality: :better } },
643
+ processors: [:rotator, :ocr]
644
+ ```
645
+
646
+ then both the :rotator processor and the :ocr processor would receive the
647
+ options `{ quality: :better }`. This parameter may not mean anything to one
648
+ or more or the processors, and they are expected to ignore it.
649
+
650
+ _NOTE: Because processors operate by turning the original attachment into the
651
+ styles, no processors will be run if there are no styles defined._
652
+
653
+ If you're interested in caching your thumbnail's width, height and size in the
654
+ database, take a look at the [paperclip-meta](https://github.com/teeparham/paperclip-meta) gem.
655
+
656
+ Also, if you're interested in generating the thumbnail on-the-fly, you might want
657
+ to look into the [attachment_on_the_fly](https://github.com/drpentode/Attachment-on-the-Fly) gem.
658
+
659
+ ---
660
+
661
+ Events
662
+ ------
663
+
664
+ Before and after the Post Processing step, Paperclip calls back to the model
665
+ with a few callbacks, allowing the model to change or cancel the processing
666
+ step. The callbacks are `before_post_process` and `after_post_process` (which
667
+ are called before and after the processing of each attachment), and the
668
+ attachment-specific `before_<attachment>_post_process` and
669
+ `after_<attachment>_post_process`. The callbacks are intended to be as close to
670
+ normal ActiveRecord callbacks as possible, so if you return false (specifically
671
+ \- returning nil is not the same) in a `before_filter`, the post processing step
672
+ will halt. Returning false in an `after_filter` will not halt anything, but you
673
+ can access the model and the attachment if necessary.
674
+
675
+ _NOTE: Post processing will not even **start** if the attachment is not valid
676
+ according to the validations. Your callbacks and processors will **only** be
677
+ called with valid attachments._
678
+
679
+ ```ruby
680
+ class Message < ActiveRecord::Base
681
+ has_attached_file :asset, styles: {thumb: "100x100#"}
682
+
683
+ before_post_process :skip_for_audio
684
+
685
+ def skip_for_audio
686
+ ! %w(audio/ogg application/ogg).include?(asset_content_type)
687
+ end
688
+ end
689
+ ```
690
+
691
+ ---
692
+
693
+ URI Obfuscation
694
+ ---------------
695
+
696
+ Paperclip has an interpolation called `:hash` for obfuscating filenames of
697
+ publicly-available files.
698
+
699
+ Example Usage:
700
+
701
+ ```ruby
702
+ has_attached_file :avatar, {
703
+ url: "/system/:hash.:extension",
704
+ hash_secret: "longSecretString"
705
+ }
706
+ ```
707
+
708
+
709
+ The `:hash` interpolation will be replaced with a unique hash made up of whatever
710
+ is specified in `:hash_data`. The default value for `:hash_data` is `":class/:attachment/:id/:style/:updated_at"`.
711
+
712
+ `:hash_secret` is required - an exception will be raised if `:hash` is used without `:hash_secret` present.
713
+
714
+ For more on this feature, read [the author's own explanation](https://github.com/thoughtbot/paperclip/pull/416)
715
+
716
+ MD5 Checksum / Fingerprint
717
+ -------
718
+
719
+ An MD5 checksum of the original file assigned will be placed in the model if it
720
+ has an attribute named fingerprint. Following the user model migration example
721
+ above, the migration would look like the following:
722
+
723
+ ```ruby
724
+ class AddAvatarFingerprintColumnToUser < ActiveRecord::Migration
725
+ def up
726
+ add_column :users, :avatar_fingerprint, :string
727
+ end
728
+
729
+ def down
730
+ remove_column :users, :avatar_fingerprint
731
+ end
732
+ end
733
+ ```
734
+
735
+ File Preservation for Soft-Delete
736
+ -------
737
+
738
+ An option is available to preserve attachments in order to play nicely with soft-deleted models. (acts_as_paranoid, paranoia, etc.)
739
+
740
+ ```ruby
741
+ has_attached_file :some_attachment, {
742
+ preserve_files: "true",
743
+ }
744
+ ```
745
+
746
+ This will prevent ```some_attachment``` from being wiped out when the model gets destroyed, so it will still exist when the object is restored later.
747
+
748
+ ---
749
+
750
+ Custom Attachment Processors
751
+ -------
752
+
753
+ Custom attachment processors can be implemented and their only requirement is
754
+ to inherit from `Paperclip::Processor` (see `lib/paperclip/processor.rb`).
755
+ For example, when `:styles` are specified for an image attachment, the
756
+ thumbnail processor (see `lib/paperclip/thumbnail.rb`) is loaded without having
757
+ to specify it as a `:processor` parameter to `has_attached_file`. When any
758
+ other processor is defined, it must be called out in the `:processors`
759
+ parameter if it is to be applied to the attachment. The thumbnail processor
760
+ uses the ImageMagick `convert` command to do the work of resizing image
761
+ thumbnails. It would be easy to create a custom processor that watermarks
762
+ an image using ImageMagick's `composite` command. Following the
763
+ implementation pattern of the thumbnail processor would be a way to implement a
764
+ watermark processor. All kinds of attachment processors can be created;
765
+ a few utility examples would be compression and encryption processors.
766
+
767
+ ---
768
+
769
+ Dynamic Configuration
770
+ ---------------------
771
+
772
+ Callable objects (lambdas, Procs) can be used in a number of places for dynamic
773
+ configuration throughout Paperclip. This strategy exists in a number of
774
+ components of the library but is most significant in the possibilities for
775
+ allowing custom styles and processors to be applied for specific model
776
+ instances, rather than applying defined styles and processors across all
777
+ instances.
778
+
779
+ ### Dynamic Styles:
780
+
781
+ Imagine a user model that had different styles based on the role of the user.
782
+ Perhaps some users are bosses (e.g. a User model instance responds to `#boss?`)
783
+ and merit a bigger avatar thumbnail than regular users. The configuration to
784
+ determine what style parameters are to be used based on the user role might
785
+ look as follows where a boss will receive a `300x300` thumbnail otherwise a
786
+ `100x100` thumbnail will be created.
787
+
788
+ ```ruby
789
+ class User < ActiveRecord::Base
790
+ has_attached_file :avatar, styles: lambda { |attachment| { thumb: (attachment.instance.boss? ? "300x300>" : "100x100>") } }
791
+ end
792
+ ```
793
+
794
+ ### Dynamic Processors:
795
+
796
+ Another contrived example is a user model that is aware of which file processors
797
+ should be applied to it (beyond the implied `thumbnail` processor invoked when
798
+ `:styles` are defined). Perhaps we have a watermark processor available and it is
799
+ only used on the avatars of certain models. The configuration for this might be
800
+ where the instance is queried for which processors should be applied to it.
801
+ Presumably some users might return `[:thumbnail, :watermark]` for its
802
+ processors, where a defined `watermark` processor is invoked after the
803
+ `thumbnail` processor already defined by Paperclip.
804
+
805
+ ```ruby
806
+ class User < ActiveRecord::Base
807
+ has_attached_file :avatar, processors: lambda { |instance| instance.processors }
808
+ attr_accessor :processors
809
+ end
810
+ ```
811
+
812
+ ---
813
+
814
+ Logging
815
+ ----------
816
+
817
+ By default, Paperclip outputs logging according to your logger level. If you want to disable logging (e.g. during testing) add this into your environment's configuration:
818
+ ```ruby
819
+ Your::Application.configure do
820
+ ...
821
+ Paperclip.options[:log] = false
822
+ ...
823
+ end
824
+ ```
825
+
826
+ More information in the [rdocs](http://www.rubydoc.info/github/thoughtbot/paperclip/Paperclip.options)
827
+
828
+ ---
829
+
830
+ Deployment
831
+ ----------
832
+
833
+ To make Capistrano symlink the `public/system` directory so that attachments
834
+ survive new deployments, set the `linked_dirs` option in your `config/deploy.rb`
835
+ file:
836
+
837
+ ```ruby
838
+ set :linked_dirs, fetch(:linked_dirs, []).push('public/system')
839
+ ```
840
+
841
+ ### Attachment Styles
842
+
843
+ Paperclip is aware of new attachment styles you have added in previous deploys. The only thing you should do after each deployment is to call
844
+ `rake paperclip:refresh:missing_styles`. It will store current attachment styles in `RAILS_ROOT/public/system/paperclip_attachments.yml`
845
+ by default. You can change it by:
846
+
847
+ ```ruby
848
+ Paperclip.registered_attachments_styles_path = '/tmp/config/paperclip_attachments.yml'
849
+ ```
850
+
851
+ Here is an example for Capistrano:
852
+
853
+ ```ruby
854
+ namespace :deploy do
855
+ desc "build missing paperclip styles"
856
+ task :build_missing_paperclip_styles do
857
+ on roles(:app) do
858
+ within release_path do
859
+ with rails_env: fetch(:rails_env) do
860
+ execute :rake, "paperclip:refresh:missing_styles"
861
+ end
862
+ end
863
+ end
864
+ end
865
+ end
866
+
867
+ after("deploy:compile_assets", "deploy:build_missing_paperclip_styles")
868
+ ```
869
+
870
+ Now you don't have to remember to refresh thumbnails in production every time you add a new style.
871
+ Unfortunately, it does not work with dynamic styles - it just ignores them.
872
+
873
+ If you already have a working app and don't want `rake paperclip:refresh:missing_styles` to refresh old pictures, you need to tell
874
+ Paperclip about existing styles. Simply create a `paperclip_attachments.yml` file by hand. For example:
875
+
876
+ ```ruby
877
+ class User < ActiveRecord::Base
878
+ has_attached_file :avatar, styles: { thumb: 'x100', croppable: '600x600>', big: '1000x1000>' }
879
+ end
880
+
881
+ class Book < ActiveRecord::Base
882
+ has_attached_file :cover, styles: { small: 'x100', large: '1000x1000>' }
883
+ has_attached_file :sample, styles: { thumb: 'x100' }
884
+ end
885
+ ```
886
+
887
+ Then in `RAILS_ROOT/public/system/paperclip_attachments.yml`:
888
+
889
+ ```yml
890
+ ---
891
+ :User:
892
+ :avatar:
893
+ - :thumb
894
+ - :croppable
895
+ - :big
896
+ :Book:
897
+ :cover:
898
+ - :small
899
+ - :large
900
+ :sample:
901
+ - :thumb
902
+ ```
903
+
904
+ ---
905
+
906
+ Testing
907
+ -------
908
+
909
+ Paperclip provides rspec-compatible matchers for testing attachments. See the
910
+ documentation on [Paperclip::Shoulda::Matchers](http://www.rubydoc.info/gems/paperclip/Paperclip/Shoulda/Matchers)
911
+ for more information.
912
+
913
+ **Parallel Tests**
914
+
915
+ Because of the default `path` for Paperclip storage, if you try to run tests in
916
+ parallel, you may find that files get overwritten because the same path is being
917
+ calculated for them in each test process. While this fix works for
918
+ parallel_tests, a similar concept should be used for any other mechanism for
919
+ running tests concurrently.
920
+
921
+ ```ruby
922
+ if ENV['PARALLEL_TEST_GROUPS']
923
+ Paperclip::Attachment.default_options[:path] = ":rails_root/public/system/:rails_env/#{ENV['TEST_ENV_NUMBER'].to_i}/:class/:attachment/:id_partition/:filename"
924
+ else
925
+ Paperclip::Attachment.default_options[:path] = ":rails_root/public/system/:rails_env/:class/:attachment/:id_partition/:filename"
926
+ end
927
+ ```
928
+
929
+ The important part here being the inclusion of `ENV['TEST_ENV_NUMBER']`, or a
930
+ similar mechanism for whichever parallel testing library you use.
931
+
932
+ **Integration Tests**
933
+
934
+ Using integration tests with FactoryGirl may save multiple copies of
935
+ your test files within the app. To avoid this, specify a custom path in
936
+ the `config/environments/test.rb` like so:
937
+
938
+ ```ruby
939
+ Paperclip::Attachment.default_options[:path] = "#{Rails.root}/spec/test_files/:class/:id_partition/:style.:extension"
940
+ ```
941
+
942
+ Then, make sure to delete that directory after the test suite runs by adding
943
+ this to `spec_helper.rb`.
944
+
945
+ ```ruby
946
+ config.after(:suite) do
947
+ FileUtils.rm_rf(Dir["#{Rails.root}/spec/test_files/"])
948
+ end
949
+ ```
950
+
951
+ **Example of test configuration with Factory Girl**
952
+
953
+
954
+ ```ruby
955
+ FactoryGirl.define do
956
+ factory :user do
957
+ avatar { File.new("#{Rails.root}/spec/support/fixtures/image.jpg") }
958
+ end
959
+ end
960
+ ```
961
+ ---
962
+
963
+ Contributing
964
+ ------------
965
+
966
+ If you'd like to contribute a feature or bugfix: Thanks! To make sure your
967
+ fix/feature has a high chance of being included, please read the following
968
+ guidelines:
969
+
970
+ 1. Post a [pull request](https://github.com/thoughtbot/paperclip/compare/).
971
+ 2. Make sure there are tests! We will not accept any patch that is not tested.
972
+ It's a rare time when explicit tests aren't needed. If you have questions
973
+ about writing tests for paperclip, please open a
974
+ [GitHub issue](https://github.com/thoughtbot/paperclip/issues/new).
975
+
976
+ Please see [`CONTRIBUTING.md`](./CONTRIBUTING.md) for more details on contributing and running test.
977
+
978
+ Thank you to all [the contributors](https://github.com/thoughtbot/paperclip/graphs/contributors)!
979
+
980
+ License
981
+ -------
982
+
983
+ Paperclip is Copyright © 2008-2016 thoughtbot, inc. It is free software, and may be
984
+ redistributed under the terms specified in the MIT-LICENSE file.
985
+
986
+ About thoughtbot
987
+ ----------------
988
+
989
+ ![thoughtbot](https://thoughtbot.com/logo.png)
990
+
991
+ Paperclip is maintained and funded by thoughtbot.
992
+ The names and logos for thoughtbot are trademarks of thoughtbot, inc.
993
+
994
+ We love open source software!
995
+ See [our other projects][community] or
996
+ [hire us][hire] to design, develop, and grow your product.
997
+
998
+ [community]: https://thoughtbot.com/community?utm_source=github
999
+ [hire]: https://thoughtbot.com?utm_source=github