paperclip 4.3.7 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +17 -0
  3. data/.github/issue_template.md +3 -0
  4. data/.hound.yml +5 -16
  5. data/.travis.yml +15 -12
  6. data/Appraisals +4 -8
  7. data/CONTRIBUTING.md +16 -5
  8. data/Gemfile +3 -8
  9. data/LICENSE +1 -1
  10. data/MIGRATING-ES.md +317 -0
  11. data/MIGRATING.md +375 -0
  12. data/NEWS +126 -31
  13. data/README.md +264 -156
  14. data/Rakefile +1 -1
  15. data/UPGRADING +12 -9
  16. data/features/basic_integration.feature +3 -2
  17. data/features/migration.feature +0 -24
  18. data/features/step_definitions/attachment_steps.rb +14 -14
  19. data/features/step_definitions/rails_steps.rb +29 -28
  20. data/features/step_definitions/s3_steps.rb +2 -2
  21. data/features/support/env.rb +1 -0
  22. data/features/support/paths.rb +1 -1
  23. data/features/support/rails.rb +0 -24
  24. data/gemfiles/4.2.gemfile +3 -5
  25. data/gemfiles/{3.2.gemfile → 5.0.gemfile} +4 -6
  26. data/lib/generators/paperclip/paperclip_generator.rb +9 -1
  27. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +1 -1
  28. data/lib/paperclip.rb +14 -12
  29. data/lib/paperclip/attachment.rb +44 -20
  30. data/lib/paperclip/attachment_registry.rb +2 -1
  31. data/lib/paperclip/callbacks.rb +8 -6
  32. data/lib/paperclip/content_type_detector.rb +3 -2
  33. data/lib/paperclip/errors.rb +3 -1
  34. data/lib/paperclip/file_command_content_type_detector.rb +1 -1
  35. data/lib/paperclip/filename_cleaner.rb +0 -1
  36. data/lib/paperclip/geometry_detector_factory.rb +3 -3
  37. data/lib/paperclip/glue.rb +1 -1
  38. data/lib/paperclip/has_attached_file.rb +7 -1
  39. data/lib/paperclip/helpers.rb +15 -11
  40. data/lib/paperclip/interpolations.rb +7 -2
  41. data/lib/paperclip/io_adapters/abstract_adapter.rb +31 -4
  42. data/lib/paperclip/io_adapters/attachment_adapter.rb +17 -6
  43. data/lib/paperclip/io_adapters/data_uri_adapter.rb +8 -8
  44. data/lib/paperclip/io_adapters/empty_string_adapter.rb +5 -4
  45. data/lib/paperclip/io_adapters/file_adapter.rb +12 -6
  46. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +8 -7
  47. data/lib/paperclip/io_adapters/identity_adapter.rb +12 -6
  48. data/lib/paperclip/io_adapters/nil_adapter.rb +8 -5
  49. data/lib/paperclip/io_adapters/registry.rb +6 -2
  50. data/lib/paperclip/io_adapters/stringio_adapter.rb +9 -6
  51. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +10 -6
  52. data/lib/paperclip/io_adapters/uri_adapter.rb +22 -17
  53. data/lib/paperclip/logger.rb +1 -1
  54. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +4 -4
  55. data/lib/paperclip/media_type_spoof_detector.rb +11 -7
  56. data/lib/paperclip/processor.rb +15 -6
  57. data/lib/paperclip/schema.rb +3 -9
  58. data/lib/paperclip/storage/filesystem.rb +13 -2
  59. data/lib/paperclip/storage/fog.rb +21 -14
  60. data/lib/paperclip/storage/s3.rb +81 -61
  61. data/lib/paperclip/style.rb +0 -1
  62. data/lib/paperclip/thumbnail.rb +22 -9
  63. data/lib/paperclip/url_generator.rb +17 -13
  64. data/lib/paperclip/validators.rb +1 -1
  65. data/lib/paperclip/validators/attachment_size_validator.rb +1 -7
  66. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +4 -0
  67. data/lib/paperclip/version.rb +3 -1
  68. data/lib/tasks/paperclip.rake +18 -4
  69. data/paperclip.gemspec +13 -10
  70. data/spec/paperclip/attachment_processing_spec.rb +2 -5
  71. data/spec/paperclip/attachment_registry_spec.rb +28 -0
  72. data/spec/paperclip/attachment_spec.rb +89 -20
  73. data/spec/paperclip/content_type_detector_spec.rb +1 -1
  74. data/spec/paperclip/file_command_content_type_detector_spec.rb +15 -1
  75. data/spec/paperclip/filename_cleaner_spec.rb +0 -1
  76. data/spec/paperclip/has_attached_file_spec.rb +24 -8
  77. data/spec/paperclip/integration_spec.rb +42 -5
  78. data/spec/paperclip/interpolations_spec.rb +9 -0
  79. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +104 -22
  80. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +6 -3
  81. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +7 -1
  82. data/spec/paperclip/io_adapters/file_adapter_spec.rb +2 -2
  83. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +47 -13
  84. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +1 -1
  85. data/spec/paperclip/io_adapters/registry_spec.rb +2 -2
  86. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +1 -1
  87. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +5 -5
  88. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +104 -11
  89. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +10 -0
  90. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +1 -1
  91. data/spec/paperclip/media_type_spoof_detector_spec.rb +41 -0
  92. data/spec/paperclip/paperclip_spec.rb +15 -45
  93. data/spec/paperclip/processor_spec.rb +4 -4
  94. data/spec/paperclip/schema_spec.rb +46 -46
  95. data/spec/paperclip/storage/fog_spec.rb +31 -0
  96. data/spec/paperclip/storage/s3_live_spec.rb +20 -14
  97. data/spec/paperclip/storage/s3_spec.rb +359 -192
  98. data/spec/paperclip/style_spec.rb +0 -1
  99. data/spec/paperclip/tempfile_spec.rb +35 -0
  100. data/spec/paperclip/thumbnail_spec.rb +43 -38
  101. data/spec/paperclip/url_generator_spec.rb +54 -44
  102. data/spec/paperclip/validators/attachment_size_validator_spec.rb +26 -20
  103. data/spec/paperclip/validators_spec.rb +5 -5
  104. data/spec/spec_helper.rb +5 -2
  105. data/spec/support/assertions.rb +12 -1
  106. data/spec/support/mock_attachment.rb +2 -0
  107. data/spec/support/mock_url_generator_builder.rb +2 -2
  108. data/spec/support/model_reconstruction.rb +11 -3
  109. data/spec/support/reporting.rb +11 -0
  110. metadata +64 -61
  111. data/cucumber/paperclip_steps.rb +0 -6
  112. data/gemfiles/4.1.gemfile +0 -19
  113. data/lib/paperclip/deprecations.rb +0 -42
  114. data/lib/paperclip/locales/de.yml +0 -18
  115. data/lib/paperclip/locales/es.yml +0 -18
  116. data/lib/paperclip/locales/ja.yml +0 -18
  117. data/lib/paperclip/locales/pt-BR.yml +0 -18
  118. data/lib/paperclip/locales/zh-CN.yml +0 -18
  119. data/lib/paperclip/locales/zh-HK.yml +0 -18
  120. data/lib/paperclip/locales/zh-TW.yml +0 -18
  121. data/spec/paperclip/deprecations_spec.rb +0 -65
  122. data/spec/support/deprecations.rb +0 -9
  123. data/spec/support/rails_helpers.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 43295d174585b0f901e4582c9a187ac89c8bfcdf
4
- data.tar.gz: 48a869b66081613bc8ecef28d9b311007f61f082
2
+ SHA256:
3
+ metadata.gz: 898cd227405301490ff021b70120159d15482f1bcf07357f32bc4f14c92a5a46
4
+ data.tar.gz: 48290676c056a90077da05f9906e8621ab2e8593634606b8bcf8e7beee28ef15
5
5
  SHA512:
6
- metadata.gz: 88697737772a0e776549b80dcf4b45e42aeb57ec3cf3432827356d410c9e2abaf3bb5072be70728798c04bc5ec844715e14de5d013dbe2debe49601c73e4ad1e
7
- data.tar.gz: 2ca1c276224bf3134d9df3a3df41a69ff4e19c35374043a2fa3c634529548875bc32b25cfc0bf61b58d792d01f0b740c90c849a794a520b97671e9efe96de3e9
6
+ metadata.gz: 589b966a2cdf5ccaafa13faa9fb9298e5501274d282aafb098260ffc5268892828ea3f8ddbe4f5ee8de8dcc365031f417577d69b3320cc558eda6b8917ede710
7
+ data.tar.gz: 1b1559aa80cac274756a923a7b943cc4c50e06d984c362764ceeda86f75d9eae2833428dffa0959eee56984e2034e091fd2811aea30b9e933713bfb0070cb107
data/.codeclimate.yml ADDED
@@ -0,0 +1,17 @@
1
+ ---
2
+ engines:
3
+ duplication:
4
+ enabled: true
5
+ config:
6
+ languages:
7
+ - ruby
8
+ fixme:
9
+ enabled: true
10
+ rubocop:
11
+ enabled: true
12
+ ratings:
13
+ paths:
14
+ - "**.rb"
15
+ exclude_paths:
16
+ - features/
17
+ - spec/
@@ -0,0 +1,3 @@
1
+ ## Deprecation notice
2
+
3
+ Paperclip is currently undergoing [deprecation in favor of ActiveStorage](https://github.com/thoughtbot/paperclip/blob/master/MIGRATING.md). Maintainers of this repository will no longer be tending to new issues. We're leaving the issues page open so Paperclip users can still see & search through old issues, and continue existing discussions if they wish.
data/.hound.yml CHANGED
@@ -20,7 +20,8 @@ AllCops:
20
20
  - "db/schema.rb"
21
21
  - 'vendor/**/*'
22
22
  - 'gemfiles/vendor/**/*'
23
- RunRailsCops: false
23
+ Rails:
24
+ Enabled: false
24
25
  DisplayCopNames: false
25
26
  StyleGuideCopsOnly: false
26
27
  Style/AccessModifierIndentation:
@@ -434,7 +435,7 @@ Style/TrailingBlankLines:
434
435
  SupportedStyles:
435
436
  - final_newline
436
437
  - final_blank_line
437
- Style/TrailingComma:
438
+ Style/TrailingCommaInLiteral:
438
439
  Description: Checks for trailing comma in parameter lists and literals.
439
440
  StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas
440
441
  Enabled: false
@@ -560,11 +561,6 @@ Rails/ActionFilter:
560
561
  - filter
561
562
  Include:
562
563
  - app/controllers/**/*.rb
563
- Rails/DefaultScope:
564
- Description: Checks if the argument passed to default_scope is a block.
565
- Enabled: true
566
- Include:
567
- - app/models/**/*.rb
568
564
  Rails/HasAndBelongsToMany:
569
565
  Description: Prefer has_many :through to has_and_belongs_to_many.
570
566
  Enabled: true
@@ -685,10 +681,6 @@ Style/DefWithParentheses:
685
681
  Description: Use def with parentheses when there are arguments.
686
682
  StyleGuide: https://github.com/bbatsov/ruby-style-guide#method-parens
687
683
  Enabled: true
688
- Style/DeprecatedHashMethods:
689
- Description: Checks for use of deprecated Hash methods.
690
- StyleGuide: https://github.com/bbatsov/ruby-style-guide#hash-key
691
- Enabled: false
692
684
  Style/Documentation:
693
685
  Description: Document classes and non-namespace modules.
694
686
  Enabled: false
@@ -840,7 +832,7 @@ Style/SelfAssignment:
840
832
  used.
841
833
  StyleGuide: https://github.com/bbatsov/ruby-style-guide#self-assignment
842
834
  Enabled: false
843
- Style/SingleSpaceBeforeFirstArg:
835
+ Style/SpaceBeforeFirstArg:
844
836
  Description: Checks that exactly one space is used between a method name and the
845
837
  first argument for method calls without parentheses.
846
838
  Enabled: true
@@ -852,7 +844,7 @@ Style/SpaceAfterComma:
852
844
  Description: Use spaces after commas.
853
845
  StyleGuide: https://github.com/bbatsov/ruby-style-guide#spaces-operators
854
846
  Enabled: true
855
- Style/SpaceAfterControlKeyword:
847
+ Style/SpaceAroundKeyword:
856
848
  Description: Use spaces after if/elsif/unless/while/until/case/when.
857
849
  Enabled: true
858
850
  Style/SpaceAfterMethodName:
@@ -881,9 +873,6 @@ Style/SpaceAroundOperators:
881
873
  Description: Use spaces around operators.
882
874
  StyleGuide: https://github.com/bbatsov/ruby-style-guide#spaces-operators
883
875
  Enabled: true
884
- Style/SpaceBeforeModifierKeyword:
885
- Description: Put a space before the modifier keyword.
886
- Enabled: true
887
876
  Style/SpaceInsideBrackets:
888
877
  Description: No spaces after [ or before ].
889
878
  StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-spaces-braces
data/.travis.yml CHANGED
@@ -1,22 +1,25 @@
1
+ language: ruby
2
+ sudo: false
3
+
1
4
  rvm:
2
- - 2.0
3
5
  - 2.1
4
- - 2.2.2
5
- - jruby-19mode
6
- - rbx-2
6
+ - 2.2
7
+ - 2.3
8
+ - 2.4
7
9
 
8
10
  script: "bundle exec rake clean spec cucumber"
9
11
 
12
+ addons:
13
+ apt:
14
+ packages:
15
+ - ghostscript
16
+
10
17
  gemfile:
11
- - gemfiles/3.2.gemfile
12
- - gemfiles/4.1.gemfile
13
18
  - gemfiles/4.2.gemfile
19
+ - gemfiles/5.0.gemfile
14
20
 
15
21
  matrix:
16
22
  fast_finish: true
17
- allow_failures:
18
- - rvm: jruby-19mode
19
- - rvm: rbx-2
20
-
21
- sudo: false
22
- cache: bundler
23
+ exclude:
24
+ - gemfile: gemfiles/5.0.gemfile
25
+ rvm: 2.1
data/Appraisals CHANGED
@@ -1,11 +1,7 @@
1
- appraise "3.2" do
2
- gem "rails", "~> 3.2.0"
3
- end
4
-
5
- appraise "4.1" do
6
- gem "rails", "~> 4.1.0"
7
- end
8
-
9
1
  appraise "4.2" do
10
2
  gem "rails", "~> 4.2.0"
11
3
  end
4
+
5
+ appraise "5.0" do
6
+ gem "rails", "~> 5.0.0"
7
+ end
data/CONTRIBUTING.md CHANGED
@@ -1,20 +1,31 @@
1
1
  Contributing
2
2
  ============
3
3
 
4
- We love pull requests. Here's a quick guide:
4
+ We love pull requests from everyone. By participating in this project, you agree
5
+ to abide by the thoughtbot [code of conduct].
6
+
7
+ [code of conduct]: https://thoughtbot.com/open-source-code-of-conduct
8
+
9
+ Here's a quick guide for contributing:
5
10
 
6
11
  1. Fork the repo.
7
12
 
8
- 2. Run the tests. We only take pull requests with passing tests, and it's great
13
+ 1. Make sure you have ImageMagick and Ghostscript installed. See [this section]
14
+ (./README.md#image-processor) of the README.
15
+
16
+ 1. Run the tests. We only take pull requests with passing tests, and it's great
9
17
  to know that you have a clean slate: `bundle && bundle exec rake`
10
18
 
11
- 3. Add a test for your change. Only refactoring and documentation changes
19
+ 1. Add a test for your change. Only refactoring and documentation changes
12
20
  require no new tests. If you are adding functionality or fixing a bug, we need
13
21
  a test!
14
22
 
15
- 4. Make the test pass.
23
+ 1. Make the test pass.
24
+
25
+ 1. Mention how your changes affect the project to other developers and users in
26
+ the `NEWS.md` file.
16
27
 
17
- 5. Push to your fork and submit a pull request.
28
+ 1. Push to your fork and submit a pull request.
18
29
 
19
30
  At this point you're waiting on us. We like to at least comment on, if not
20
31
  accept, pull requests within seven business days (most of the work on Paperclip
data/Gemfile CHANGED
@@ -3,19 +3,14 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  gem 'sqlite3', '~> 1.3.8', :platforms => :ruby
6
-
7
- gem 'jruby-openssl', :platforms => :jruby
8
- gem 'activerecord-jdbcsqlite3-adapter', :platforms => :jruby
9
-
10
- gem 'rubysl', :platforms => :rbx
11
- gem 'racc', :platforms => :rbx
12
-
13
6
  gem 'pry'
14
7
 
15
8
  # Hinting at development dependencies
16
9
  # Prevents bundler from taking a long-time to resolve
17
10
  group :development, :test do
18
- gem 'mime-types', '~> 1.16'
11
+ gem 'activerecord-import'
12
+ gem 'mime-types'
19
13
  gem 'builder'
20
14
  gem 'rubocop', require: false
15
+ gem 'rspec'
21
16
  end
data/LICENSE CHANGED
@@ -3,7 +3,7 @@ LICENSE
3
3
 
4
4
  The MIT License
5
5
 
6
- Copyright (c) 2008-2015 Jon Yurek and thoughtbot, inc.
6
+ Copyright (c) 2008-2016 Jon Yurek and thoughtbot, inc.
7
7
 
8
8
  Permission is hereby granted, free of charge, to any person obtaining a copy
9
9
  of this software and associated documentation files (the "Software"), to deal
data/MIGRATING-ES.md ADDED
@@ -0,0 +1,317 @@
1
+ # Migrando de Paperclip a ActiveStorage
2
+
3
+ Paperclip y ActiveStorage resuelven problemas similares con soluciones
4
+ similares, por lo que pasar de uno a otro es simple.
5
+
6
+ El proceso de ir desde Paperclip hacia ActiveStorage es como sigue:
7
+
8
+ 1. Implementa las migraciones a la base de datos de ActiveStorage.
9
+ 2. Configura el almacenamiento.
10
+ 3. Copia la base de datos.
11
+ 4. Copia los archivos.
12
+ 5. Actualiza tus pruebas.
13
+ 6. Actualiza tus vistas.
14
+ 7. Actualiza tus controladores.
15
+ 8. Actualiza tus modelos.
16
+
17
+ ## Implementa las migraciones a la base de datos de ActiveStorage
18
+
19
+ Sigue [las instrucciones para instalar ActiveStorage]. Muy probablemente vas a
20
+ querer agregar la gema `mini_magick` a tu Gemfile.
21
+
22
+
23
+ ```sh
24
+ rails active_storage:install
25
+ ```
26
+
27
+ [las instrucciones para instalar ActiveStorage]: https://github.com/rails/rails/blob/master/activestorage/README.md#installation
28
+
29
+ ## Configura el almacenamiento
30
+
31
+ De nuevo, sigue [las instrucciones para configurar ActiveStorage].
32
+
33
+ [las instrucciones para configurar ActiveStorage]: http://edgeguides.rubyonrails.org/active_storage_overview.html#setup
34
+
35
+ ## Copia la base de datos.
36
+
37
+ Las tablas `active_storage_blobs` y`active_storage_attachments` son en donde
38
+ ActiveStorage espera encontrar los metadatos del archivo. Paperclip almacena los
39
+ metadatos del archivo directamente en en la tabla del objeto asociado.
40
+
41
+ Vas a necesitar escribir una migración para esta conversión. Proveer un script
42
+ simple, es complicado porque están involucrados tus modelos. ¡Pero lo
43
+ intentaremos!
44
+
45
+ Así sería para un `User` con un `avatar` en Paperclip:
46
+
47
+ ```ruby
48
+ class User < ApplicationRecord
49
+ has_attached_file :avatar
50
+ end
51
+ ```
52
+
53
+ Tus migraciones de Paperclip producirán una tabla como la siguiente:
54
+
55
+ ```ruby
56
+ create_table "users", force: :cascade do |t|
57
+ t.string "avatar_file_name"
58
+ t.string "avatar_content_type"
59
+ t.integer "avatar_file_size"
60
+ t.datetime "avatar_updated_at"
61
+ end
62
+ ```
63
+
64
+ Y tu la convertirás en estas tablas:
65
+
66
+ ```ruby
67
+ create_table "active_storage_attachments", force: :cascade do |t|
68
+ t.string "name", null: false
69
+ t.string "record_type", null: false
70
+ t.integer "record_id", null: false
71
+ t.integer "blob_id", null: false
72
+ t.datetime "created_at", null: false
73
+ t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
74
+ t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
75
+ end
76
+ ```
77
+
78
+ ```ruby
79
+ create_table "active_storage_blobs", force: :cascade do |t|
80
+ t.string "key", null: false
81
+ t.string "filename", null: false
82
+ t.string "content_type"
83
+ t.text "metadata"
84
+ t.bigint "byte_size", null: false
85
+ t.string "checksum", null: false
86
+ t.datetime "created_at", null: false
87
+ t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
88
+ end
89
+ ```
90
+
91
+ Así que asumiendo que quieres dejar los archivos en el mismo lugar, _esta es tu
92
+ migración_. De otra forma, ve la siguiente sección primero y modifica la
93
+ migración como corresponda.
94
+
95
+ ```ruby
96
+ Dir[Rails.root.join("app/models/**/*.rb")].sort.each { |file| require file }
97
+
98
+ class ConvertToActiveStorage < ActiveRecord::Migration[5.2]
99
+ require 'open-uri'
100
+
101
+ def up
102
+ # postgres
103
+ get_blob_id = 'LASTVAL()'
104
+ # mariadb
105
+ # get_blob_id = 'LAST_INSERT_ID()'
106
+ # sqlite
107
+ # get_blob_id = 'LAST_INSERT_ROWID()'
108
+
109
+ active_storage_blob_statement = ActiveRecord::Base.connection.raw_connection.prepare(<<-SQL)
110
+ INSERT INTO active_storage_blobs (
111
+ key, filename, content_type, metadata, byte_size,
112
+ checksum, created_at
113
+ ) VALUES (?, ?, ?, '{}', ?, ?, ?)
114
+ SQL
115
+
116
+ active_storage_attachment_statement = ActiveRecord::Base.connection.raw_connection.prepare(<<-SQL)
117
+ INSERT INTO active_storage_attachments (
118
+ name, record_type, record_id, blob_id, created_at
119
+ ) VALUES (?, ?, ?, #{get_blob_id}, ?)
120
+ SQL
121
+
122
+ models = ActiveRecord::Base.descendants.reject(&:abstract_class?)
123
+
124
+ transaction do
125
+ models.each do |model|
126
+ attachments = model.column_names.map do |c|
127
+ if c =~ /(.+)_file_name$/
128
+ $1
129
+ end
130
+ end.compact
131
+
132
+ model.find_each.each do |instance|
133
+ attachments.each do |attachment|
134
+ active_storage_blob_statement.execute(
135
+ key(instance, attachment),
136
+ instance.send("#{attachment}_file_name"),
137
+ instance.send("#{attachment}_content_type"),
138
+ instance.send("#{attachment}_file_size"),
139
+ checksum(instance.send(attachment)),
140
+ instance.updated_at.iso8601
141
+ )
142
+
143
+ active_storage_attachment_statement.
144
+ execute(attachment, model.name, instance.id, instance.updated_at.iso8601)
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ active_storage_attachment_statement.close
151
+ active_storage_blob_statement.close
152
+ end
153
+
154
+ def down
155
+ raise ActiveRecord::IrreversibleMigration
156
+ end
157
+
158
+ private
159
+
160
+ def key(instance, attachment)
161
+ SecureRandom.uuid
162
+ # Alternativamente:
163
+ # instance.send("#{attachment}_file_name")
164
+ end
165
+
166
+ def checksum(attachment)
167
+ # archivos locales almacenados en disco:
168
+ url = attachment.path
169
+ Digest::MD5.base64digest(File.read(url))
170
+
171
+ # archivos remotos almacenados en la computadora de alguién más:
172
+ # url = attachment.url
173
+ # Digest::MD5.base64digest(Net::HTTP.get(URI(url)))
174
+ end
175
+ end
176
+ ```
177
+
178
+ ## Copia los archivos
179
+
180
+ La migración de arriba deja los archivos como estaban. Sin embargo,
181
+ los servicios de Paperclip y ActiveStorage utilizan diferentes ubicaciones.
182
+
183
+ Por defecto, Paperclip se ve así:
184
+
185
+ ```
186
+ public/system/users/avatars/000/000/004/original/the-mystery-of-life.png
187
+ ```
188
+
189
+ Y ActiveStorage se ve así:
190
+
191
+ ```
192
+ storage/xM/RX/xMRXuT6nqpoiConJFQJFt6c9
193
+ ```
194
+
195
+ Ese `xMRXuT6nqpoiConJFQJFt6c9` es el valor de `active_storage_blobs.key`. En la
196
+ migración de arriba usamos simplemente el nombre del archivo, pero tal vez
197
+ quieras usar un UUID.
198
+
199
+ Migrando los archivos en un hospedaje externo (S3, Azure Storage, GCS, etc.)
200
+ está fuera del alcance de este documento inicial. Así es como se vería para un
201
+ almacenamiento local:
202
+
203
+ ```ruby
204
+ #!bin/rails runner
205
+
206
+ class ActiveStorageBlob < ActiveRecord::Base
207
+ end
208
+
209
+ class ActiveStorageAttachment < ActiveRecord::Base
210
+ belongs_to :blob, class_name: 'ActiveStorageBlob'
211
+ belongs_to :record, polymorphic: true
212
+ end
213
+
214
+ ActiveStorageAttachment.find_each do |attachment|
215
+ name = attachment.name
216
+
217
+ source = attachment.record.send(name).path
218
+ dest_dir = File.join(
219
+ "storage",
220
+ attachment.blob.key.first(2),
221
+ attachment.blob.key.first(4).last(2))
222
+ dest = File.join(dest_dir, attachment.blob.key)
223
+
224
+ FileUtils.mkdir_p(dest_dir)
225
+ puts "Moving #{source} to #{dest}"
226
+ FileUtils.cp(source, dest)
227
+ end
228
+ ```
229
+
230
+ ## Actualiza tus pruebas
231
+
232
+ En lugar de utilizar `have_attached_file`, será necesario que escribas tu propio
233
+ matcher. Aquí hay un matcher similar _en espíritu_ al que Paperclip provee:
234
+
235
+
236
+ ```ruby
237
+ RSpec::Matchers.define :have_attached_file do |name|
238
+ matches do |record|
239
+ file = record.send(name)
240
+ file.respond_to?(:variant) && file.respond_to?(:attach)
241
+ end
242
+ end
243
+ ```
244
+
245
+ ## Actualiza tus vistas
246
+
247
+ En Paperclip se ven así:
248
+
249
+ ```ruby
250
+ image_tag @user.avatar.url(:medium)
251
+ ```
252
+
253
+ En ActiveStorage se ven así:
254
+
255
+ ```ruby
256
+ image_tag @user.avatar.variant(resize: "250x250")
257
+ ```
258
+
259
+ ## Actualiza tus controladores
260
+
261
+ Esto no debería _requerir_ ningúna actualización. Sin embargo, si te fijas en
262
+ el schema de tu base de datos, notaras un join.
263
+
264
+ Por ejemplo si tu controlador tiene:
265
+
266
+ ```ruby
267
+ def index
268
+ @users = User.all.order(:name)
269
+ end
270
+ ```
271
+
272
+ Y tu vista tiene:
273
+
274
+ ```
275
+ <ul>
276
+ <% @users.each do |user| %>
277
+ <li><%= image_tag user.avatar.variant(resize: "10x10"), alt: user.name %></li>
278
+ <% end %>
279
+ </ul>
280
+ ```
281
+
282
+ Vas a terminar con un n+1, ya que descargas cada archivo adjunto dentro del
283
+ bucle.
284
+
285
+ Así que mientras que el controlador y el modelo funcionarán sin ningún cambio,
286
+ tal vez quieras revisar dos veces tus bucles y agregar `includes` en dónde haga
287
+ falta.
288
+
289
+ ActiveStorage agrega `avatar_attachment` y `avatar_blob` a las relaciones del
290
+ tipo `has-one`, así como `avatar_attachments` y `avatar_blobs` a las relaciones
291
+ de tipo `has-many`:
292
+
293
+ ```ruby
294
+ def index
295
+ @users = User.all.order(:name).includes(:avatar_attachment)
296
+ end
297
+ ```
298
+
299
+ ## Actualiza tus modelos
300
+
301
+ Sigue [la guía sobre cómo adjuntar archivos a los registros]. Por ejemplo, un
302
+ `User` con un `avatar` se representa como:
303
+
304
+ ```ruby
305
+ class User < ApplicationRecord
306
+ has_one_attached :avatar
307
+ end
308
+ ```
309
+
310
+ Cualquier cambio de tamaño se hace en la vista como un `variant`.
311
+
312
+ [la guía sobre cómo adjuntar archivos a los registros]: http://edgeguides.rubyonrails.org/active_storage_overview.html#attaching-files-to-records
313
+
314
+ ## Quita Paperclip
315
+
316
+ Quita la gema de tu `Gemfile` y corre `bundle`. Corre tus pruebas porque ya
317
+ terminaste!