diff --git a/Gemfile b/Gemfile index f801c109d..8dde556bb 100644 --- a/Gemfile +++ b/Gemfile @@ -40,7 +40,6 @@ gem "omniauth-facebook", "~> 8.0.0" gem "omniauth-google-oauth2", "~> 1.0.0" gem "omniauth-rails_csrf_protection", "~> 1.0.0" gem "omniauth-twitter", "~> 1.4.0" -gem "paperclip", "~> 6.1.0" gem "paranoia", "~> 2.4.3" gem "pg", "~> 1.2.3" gem "pg_search", "~> 2.3.5" diff --git a/Gemfile.lock b/Gemfile.lock index 59d23bcca..efa05e5f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -373,9 +373,6 @@ GEM mime-types (3.3.1) mime-types-data (~> 3.2015) mime-types-data (3.2021.0704) - mimemagic (0.3.10) - nokogiri (~> 1) - rake mini_magick (4.11.0) mini_mime (1.1.0) mini_portile2 (2.6.1) @@ -430,12 +427,6 @@ GEM omniauth-oauth (~> 1.1) rack orm_adapter (0.5.0) - paperclip (6.1.0) - activemodel (>= 4.2.0) - activesupport (>= 4.2.0) - mime-types - mimemagic (~> 0.3.0) - terrapin (~> 0.6.0) parallel (1.20.1) paranoia (2.4.3) activerecord (>= 4.0, < 6.2) @@ -753,7 +744,6 @@ DEPENDENCIES omniauth-google-oauth2 (~> 1.0.0) omniauth-rails_csrf_protection (~> 1.0.0) omniauth-twitter (~> 1.4.0) - paperclip (~> 6.1.0) paranoia (~> 2.4.3) pg (~> 1.2.3) pg_search (~> 2.3.5) diff --git a/app/components/attachable/fields_component.html.erb b/app/components/attachable/fields_component.html.erb index 54f91cb2a..e5e9854a6 100644 --- a/app/components/attachable/fields_component.html.erb +++ b/app/components/attachable/fields_component.html.erb @@ -7,7 +7,7 @@ <%= f.text_field :title, placeholder: t("#{plural_name}.form.title_placeholder") %> - <% if attachable.storage_attachment.attached? && attachable.storage_attachment.image? %> + <% if attachable.attachment.attached? && attachable.attachment.image? %> <%= render_image(attachable, :thumb, false) %> <% end %> diff --git a/app/components/attachable/fields_component.rb b/app/components/attachable/fields_component.rb index fac93f7be..ae217456a 100644 --- a/app/components/attachable/fields_component.rb +++ b/app/components/attachable/fields_component.rb @@ -24,7 +24,7 @@ class Attachable::FieldsComponent < ApplicationComponent end def file_name - attachable.storage_attachment.filename if attachable.storage_attachment.attached? + attachable.attachment_file_name end def destroy_link diff --git a/app/controllers/direct_uploads_controller.rb b/app/controllers/direct_uploads_controller.rb index 9bc565a29..ca992cd8e 100644 --- a/app/controllers/direct_uploads_controller.rb +++ b/app/controllers/direct_uploads_controller.rb @@ -15,9 +15,9 @@ class DirectUploadsController < ApplicationController @direct_upload.relation.set_cached_attachment_from_attachment render json: { cached_attachment: @direct_upload.relation.cached_attachment, - filename: @direct_upload.relation.storage_attachment.filename.to_s, + filename: @direct_upload.relation.attachment_file_name, destroy_link: render_destroy_upload_link(@direct_upload), - attachment_url: polymorphic_path(@direct_upload.relation.storage_attachment) } + attachment_url: polymorphic_path(@direct_upload.relation.attachment) } else render json: { errors: @direct_upload.errors[:attachment].join(", ") }, status: :unprocessable_entity diff --git a/app/helpers/documents_helper.rb b/app/helpers/documents_helper.rb index 742a88acf..9110e45b8 100644 --- a/app/helpers/documents_helper.rb +++ b/app/helpers/documents_helper.rb @@ -3,7 +3,7 @@ module DocumentsHelper info_text = "#{document.humanized_content_type} | #{number_to_human_size(document.attachment_file_size)}" link_to safe_join([document.title, tag.small("(#{info_text})")], " "), - document.storage_attachment, + document.attachment, target: "_blank", title: t("shared.target_blank") end diff --git a/app/helpers/welcome_helper.rb b/app/helpers/welcome_helper.rb index 0f26b3a73..cb77252d3 100644 --- a/app/helpers/welcome_helper.rb +++ b/app/helpers/welcome_helper.rb @@ -25,7 +25,7 @@ module WelcomeHelper def calculate_image_path(recommended, image_default) if recommended.respond_to?(:image) && recommended.image.present? && - recommended.image.storage_attachment.attached? + recommended.image.attachment.attached? recommended.image.variant(:medium) elsif image_default.present? image_default diff --git a/app/models/concerns/attachable.rb b/app/models/concerns/attachable.rb index a8fda86ac..f1a069bcb 100644 --- a/app/models/concerns/attachable.rb +++ b/app/models/concerns/attachable.rb @@ -3,14 +3,12 @@ module Attachable extend ActiveSupport::Concern included do + has_attachment :attachment attr_accessor :cached_attachment - # Disable paperclip security validation due to polymorphic configuration - # Paperclip do not allow to use Procs on valiations definition - do_not_validate_attachment_file_type :attachment validate :attachment_presence - validate :validate_attachment_content_type, if: -> { storage_attachment.attached? } - validate :validate_attachment_size, if: -> { storage_attachment.attached? } + validate :validate_attachment_content_type, if: -> { attachment.attached? } + validate :validate_attachment_size, if: -> { attachment.attached? } before_validation :set_attachment_from_cached_attachment, if: -> { cached_attachment.present? } end @@ -22,43 +20,35 @@ module Attachable end def set_cached_attachment_from_attachment - self.cached_attachment = storage_attachment.signed_id + self.cached_attachment = attachment.signed_id end def set_attachment_from_cached_attachment - self.storage_attachment = cached_attachment + self.attachment = cached_attachment + end - if filesystem_storage? - File.open(file_path) do |file| - self.paperclip_attachment = file - end - else - self.paperclip_attachment = URI.parse(cached_attachment).open - end + def attachment_file_name + attachment.filename.to_s if attachment.attached? end def attachment_content_type - storage_attachment.blob.content_type if storage_attachment.attached? + attachment.blob.content_type if attachment.attached? end def attachment_file_size - if storage_attachment.attached? - storage_attachment.blob.byte_size + if attachment.attached? + attachment.blob.byte_size else 0 end end def file_path - ActiveStorage::Blob.service.path_for(storage_attachment.blob.key) + ActiveStorage::Blob.service.path_for(attachment.blob.key) end private - def filesystem_storage? - Paperclip::Attachment.default_options[:storage] == :filesystem - end - def validate_attachment_size if association_class && attachment_file_size > max_file_size.megabytes errors.add(:attachment, I18n.t("#{model_name.plural}.errors.messages.in_between", @@ -77,7 +67,7 @@ module Attachable end def attachment_presence - unless storage_attachment.attached? + unless attachment.attached? errors.add(:attachment, I18n.t("errors.messages.blank")) end end diff --git a/app/models/concerns/has_attachment.rb b/app/models/concerns/has_attachment.rb index 8fcafa3ec..accca53c2 100644 --- a/app/models/concerns/has_attachment.rb +++ b/app/models/concerns/has_attachment.rb @@ -2,25 +2,17 @@ module HasAttachment extend ActiveSupport::Concern class_methods do - def has_attachment(attribute, paperclip_options = {}) - has_one_attached :"storage_#{attribute}" - - define_method :"storage_#{attribute}=" do |file| - if file.is_a?(IO) - send(:"storage_#{attribute}").attach(io: file, filename: File.basename(file.path)) - elsif file.nil? - send(:"storage_#{attribute}").detach - else - send(:"storage_#{attribute}").attach(file) - end - end - - has_attached_file attribute, paperclip_options - alias_method :"paperclip_#{attribute}=", :"#{attribute}=" + def has_attachment(attribute) + has_one_attached attribute define_method :"#{attribute}=" do |file| - send(:"storage_#{attribute}=", file) - send(:"paperclip_#{attribute}=", file) + if file.is_a?(IO) + send(attribute).attach(io: file, filename: File.basename(file.path)) + elsif file.nil? + send(attribute).detach + else + send(attribute).attach(file) + end end end end diff --git a/app/models/direct_upload.rb b/app/models/direct_upload.rb index 66a9d45ab..cd562ca07 100644 --- a/app/models/direct_upload.rb +++ b/app/models/direct_upload.rb @@ -34,7 +34,7 @@ class DirectUpload end def save_attachment - @relation.storage_attachment.blob.save! + @relation.attachment.blob.save! end def persisted? @@ -53,7 +53,7 @@ class DirectUpload def relation_attributtes { - storage_attachment: @attachment, + attachment: @attachment, cached_attachment: @cached_attachment, user: @user } diff --git a/app/models/document.rb b/app/models/document.rb index 4b9349f3e..9a48ed615 100644 --- a/app/models/document.rb +++ b/app/models/document.rb @@ -1,11 +1,6 @@ class Document < ApplicationRecord include Attachable - has_attachment :attachment, url: "/system/:class/:attachment/:id_partition/:style/:hash.:extension", - hash_data: ":class/:style/:custom_hash_data", - use_timestamp: false, - hash_secret: Rails.application.secrets.secret_key_base - belongs_to :user belongs_to :documentable, polymorphic: true, touch: true @@ -16,23 +11,10 @@ class Document < ApplicationRecord scope :admin, -> { where(admin: true) } - Paperclip.interpolates :custom_hash_data do |attachment, _style| - attachment.instance.custom_hash_data(attachment) - end - def self.humanized_accepted_content_types Setting.accepted_content_types_for("documents").join(", ") end - def custom_hash_data(attachment) - original_filename = if attachment.instance.persisted? - attachment.instance.title - else - attachment.instance.attachment_file_name - end - "#{attachment.instance.user_id}/#{original_filename}" - end - def humanized_content_type attachment_content_type.split("/").last.upcase end diff --git a/app/models/image.rb b/app/models/image.rb index 098515114..eda89ecc8 100644 --- a/app/models/image.rb +++ b/app/models/image.rb @@ -1,16 +1,6 @@ class Image < ApplicationRecord include Attachable - has_attachment :attachment, styles: { - large: "x#{Setting["uploads.images.min_height"]}", - medium: "300x300#", - thumb: "140x245#" - }, - url: "/system/:class/:attachment/:id_partition/:style/:hash.:extension", - hash_data: ":class/:style", - use_timestamp: false, - hash_secret: Rails.application.secrets.secret_key_base - def self.styles { large: { resize: "x#{Setting["uploads.images.min_height"]}" }, @@ -27,7 +17,7 @@ class Image < ApplicationRecord validates :user_id, presence: true validates :imageable_id, presence: true, if: -> { persisted? } validates :imageable_type, presence: true, if: -> { persisted? } - validate :validate_image_dimensions, if: -> { storage_attachment.attached? && storage_attachment.new_record? } + validate :validate_image_dimensions, if: -> { attachment.attached? && attachment.new_record? } def self.max_file_size Setting["uploads.images.max_size"].to_i @@ -51,9 +41,9 @@ class Image < ApplicationRecord def variant(style) if style - storage_attachment.variant(self.class.styles[style]) + attachment.variant(self.class.styles[style]) else - storage_attachment + attachment end end @@ -71,10 +61,10 @@ class Image < ApplicationRecord if accepted_content_types.include?(attachment_content_type) return true if imageable_class == Widget::Card - storage_attachment.analyze unless storage_attachment.analyzed? + attachment.analyze unless attachment.analyzed? - width = storage_attachment.metadata[:width] - height = storage_attachment.metadata[:height] + width = attachment.metadata[:width] + height = attachment.metadata[:height] min_width = Setting["uploads.images.min_width"].to_i min_height = Setting["uploads.images.min_height"].to_i errors.add(:attachment, :min_image_width, required_min_width: min_width) if width < min_width diff --git a/app/models/site_customization/image.rb b/app/models/site_customization/image.rb index 8648cd046..c9c41ed6a 100644 --- a/app/models/site_customization/image.rb +++ b/app/models/site_customization/image.rb @@ -14,9 +14,7 @@ class SiteCustomization::Image < ApplicationRecord has_attachment :image validates :name, presence: true, uniqueness: true, inclusion: { in: VALID_IMAGES.keys } - do_not_validate_attachment_file_type :image - validates :image, file_content_type: { allow: ["image/png", "image/jpeg"] } - + validates :image, file_content_type: { allow: ["image/png", "image/jpeg"], if: -> { image.attached? }} validate :check_image def self.all_images @@ -40,21 +38,21 @@ class SiteCustomization::Image < ApplicationRecord end def persisted_image - storage_image if persisted_attachment? + image if persisted_attachment? end def persisted_attachment? - storage_image.attachment&.persisted? + image.attachment&.persisted? end private def check_image - return unless image? + return unless image.attached? - storage_image.analyze unless storage_image.analyzed? - width = storage_image.metadata[:width] - height = storage_image.metadata[:height] + image.analyze unless image.analyzed? + width = image.metadata[:width] + height = image.metadata[:height] if name == "logo_header" errors.add(:image, :image_width, required_width: required_width) unless width <= required_width diff --git a/app/views/admin/milestones/_milestones.html.erb b/app/views/admin/milestones/_milestones.html.erb index ac4d599a8..43479ce86 100644 --- a/app/views/admin/milestones/_milestones.html.erb +++ b/app/views/admin/milestones/_milestones.html.erb @@ -47,7 +47,7 @@ <% if milestone.documents.present? %> <% milestone.documents.each do |document| %> <%= link_to document.title, - document.storage_attachment, + document.attachment, target: "_blank", rel: "nofollow" %>
<% end %> diff --git a/app/views/admin/poll/questions/answers/documents.html.erb b/app/views/admin/poll/questions/answers/documents.html.erb index c322bcdaa..4c0396849 100644 --- a/app/views/admin/poll/questions/answers/documents.html.erb +++ b/app/views/admin/poll/questions/answers/documents.html.erb @@ -33,7 +33,7 @@ <% @answer.documents.each do |document| %> - <%= link_to document.title, document.storage_attachment %> + <%= link_to document.title, document.attachment %> <%= render Admin::TableActionsComponent.new(document, @@ -42,7 +42,7 @@ ) do |actions| %> <%= actions.action(:download, text: t("documents.buttons.download_document"), - path: document.storage_attachment, + path: document.attachment, target: "_blank", rel: "nofollow") %> diff --git a/app/views/admin/site_customization/documents/index.html.erb b/app/views/admin/site_customization/documents/index.html.erb index f7a8e6409..4f3f93497 100644 --- a/app/views/admin/site_customization/documents/index.html.erb +++ b/app/views/admin/site_customization/documents/index.html.erb @@ -21,9 +21,9 @@ <% @documents.each do |document| %> <%= document.title %> - <%= document.storage_attachment.content_type %> - <%= number_to_human_size(document.storage_attachment.byte_size) %> - <%= link_to document.title, document.storage_attachment, target: :blank %> + <%= document.attachment.content_type %> + <%= number_to_human_size(document.attachment.byte_size) %> + <%= link_to document.title, document.attachment, target: :blank %>
<%= render Admin::TableActionsComponent.new( diff --git a/app/views/admin/site_customization/images/index.html.erb b/app/views/admin/site_customization/images/index.html.erb index 43da53e9e..354c3626c 100644 --- a/app/views/admin/site_customization/images/index.html.erb +++ b/app/views/admin/site_customization/images/index.html.erb @@ -16,7 +16,7 @@ <%= form_for([:admin, image], html: { id: "edit_#{dom_id(image)}" }) do |f| %>
- <%= image_tag image.storage_image if image.persisted_attachment? %> + <%= image_tag image.image if image.persisted_attachment? %> <%= f.file_field :image, label: false %>
diff --git a/app/views/dashboard/_document.html.erb b/app/views/dashboard/_document.html.erb index e91efb98b..d59177a30 100644 --- a/app/views/dashboard/_document.html.erb +++ b/app/views/dashboard/_document.html.erb @@ -1,5 +1,5 @@

- <%= link_to document.storage_attachment, target: "_blank" do %> + <%= link_to document.attachment, target: "_blank" do %> <%= document.title %> (<%= document.humanized_content_type %>  |  diff --git a/app/views/documents/_document.html.erb b/app/views/documents/_document.html.erb index 67c61216b..977e3acc4 100644 --- a/app/views/documents/_document.html.erb +++ b/app/views/documents/_document.html.erb @@ -1,6 +1,6 @@

  • <%= link_to t("documents.buttons.download_document"), - document.storage_attachment, target: "_blank", + document.attachment, target: "_blank", rel: "nofollow", class: "button hollow medium float-right" %> <%= document.title %> diff --git a/app/views/milestones/_milestone.html.erb b/app/views/milestones/_milestone.html.erb index ce8ea12bc..52f8e6956 100644 --- a/app/views/milestones/_milestone.html.erb +++ b/app/views/milestones/_milestone.html.erb @@ -37,7 +37,7 @@ <% milestone.documents.each do |document| %> <%= link_to document.title, - document.storage_attachment, + document.attachment, target: "_blank", rel: "nofollow" %>
    diff --git a/app/views/polls/_gallery.html.erb b/app/views/polls/_gallery.html.erb index e62827908..43ac86cf6 100644 --- a/app/views/polls/_gallery.html.erb +++ b/app/views/polls/_gallery.html.erb @@ -18,8 +18,8 @@ <% answer.images.reverse.each_with_index do |image, index| %>
  • - <%= link_to image.storage_attachment, target: "_blank" do %> - <%= image_tag image.storage_attachment, + <%= link_to image.attachment, target: "_blank" do %> + <%= image_tag image.attachment, class: "orbit-image", alt: image.title.unicode_normalize %> <% end %> diff --git a/app/views/polls/show.html.erb b/app/views/polls/show.html.erb index 69272441a..1aa0e89ec 100644 --- a/app/views/polls/show.html.erb +++ b/app/views/polls/show.html.erb @@ -86,7 +86,7 @@ <% answer.documents.each do |document| %> <%= link_to document.title, - document.storage_attachment, + document.attachment, target: "_blank", rel: "nofollow" %>
    <% end %> diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb deleted file mode 100644 index 97a4079d9..000000000 --- a/config/initializers/paperclip.rb +++ /dev/null @@ -1,13 +0,0 @@ -class Paperclip::UrlGenerator - private - - # Code copied from the paperclip gem, only replacing - # `URI.escape` with `URI::DEFAULT_PARSER.escape` - def escape_url(url) - if url.respond_to?(:escape) - url.escape - else - URI::DEFAULT_PARSER.escape(url).gsub(escape_regex) { |m| "%#{m.ord.to_s(16).upcase}" } - end - end -end diff --git a/lib/tasks/active_storage.rake b/lib/tasks/active_storage.rake index 548d5cfc9..2f65e829b 100644 --- a/lib/tasks/active_storage.rake +++ b/lib/tasks/active_storage.rake @@ -1,98 +1,9 @@ -# This code is based on Thoughtbot's guide to migrating from Paperclip -# to Active Storage: -# https://github.com/thoughtbot/paperclip/blob/master/MIGRATING.md namespace :active_storage do - desc "Copy paperclip's attachment database columns to active storage" - task migrate_from_paperclip: :environment do - logger = ApplicationLogger.new - connection = ActiveRecord::Base.connection.raw_connection - statement_name = "active_storage_statement" - - unless connection.exec("SELECT COUNT(*) FROM pg_prepared_statements WHERE name='#{statement_name}'").each_row.to_a[0][0] > 0 - connection.prepare(statement_name, <<-SQL) - with rows as( - INSERT INTO active_storage_blobs ( - key, filename, content_type, metadata, byte_size, checksum, created_at - ) VALUES ($1, $2, $3, '{}', $4, $5, $6) RETURNING id - ) - INSERT INTO active_storage_attachments ( - name, record_type, record_id, blob_id, created_at - ) VALUES ($7, $8, $9, (SELECT id FROM rows), $10) - SQL - end - - Rails.application.eager_load! - models = ActiveRecord::Base.descendants.reject(&:abstract_class?) - paperclip_storage = Paperclip::Attachment.default_options[:storage] - - ActiveRecord::Base.transaction do - models.each do |model| - next if model.name == "OldPassword" && !model.table_exists? - - attachments = model.column_names.map do |c| - if c =~ /(.+)_file_name$/ - $1 - end - end.compact - - if attachments.blank? - next - end - - model.find_each.each do |instance| - attachments.each do |attachment| - next if instance.send(:"storage_#{attachment}").attached? - - source = if paperclip_storage == :filesystem - instance.send(attachment).path - else - instance.send(attachment).url - end - - next if source.blank? || source == "/images/original/missing.png" - - file = if paperclip_storage == :filesystem - File.read(source) if File.exist?(source) - else - Net::HTTP.get(URI(source)) - end - - connection.exec_prepared( - statement_name, [ - SecureRandom.uuid, # Alternatively instance.send("#{attachment}_file_name"), - instance.send("#{attachment}_file_name"), - instance.send("#{attachment}_content_type"), - instance.send("#{attachment}_file_size"), - file && Digest::MD5.base64digest(file) || SecureRandom.hex(32), - instance.updated_at.iso8601, - "storage_#{attachment}", - model.name, - instance.id, - instance.updated_at.iso8601 - ]) - end - end - end - end - - ActiveStorage::Attachment.find_each do |attachment| - blob = attachment.blob - - next if blob.service.exist?(blob.key) || !attachment.record - - name = attachment.name.delete_prefix("storage_") - paperclip_attachment = attachment.record.send(name) - - next unless paperclip_attachment.exists? - - source_file = if paperclip_storage == :filesystem - paperclip_attachment.path - else - URI.parse(paperclip_attachment.url).open.read - end - - logger.info "Copying #{paperclip_attachment.url} to active storage" - blob.service.upload(blob.key, source_file) - end + desc "Updates ActiveStorage::Attachment old records created when we were also using paperclip" + task remove_paperclip_compatibility_in_existing_attachments: :environment do + ApplicationLogger.new.info "Updating Active Storage attachment records" + ActiveStorage::Attachment.where("name ILIKE 'storage_%'") + .where.not(record_type: "Ckeditor::Asset") + .update_all("name = replace(name, 'storage_', '')") end end diff --git a/lib/tasks/consul.rake b/lib/tasks/consul.rake index a45012ab5..6bd19134b 100644 --- a/lib/tasks/consul.rake +++ b/lib/tasks/consul.rake @@ -2,10 +2,10 @@ namespace :consul do desc "Runs tasks needed to upgrade to the latest version" task execute_release_tasks: ["settings:rename_setting_keys", "settings:add_new_settings", - "execute_release_1.4.0_tasks"] + "execute_release_1.5.0_tasks"] - desc "Runs tasks needed to upgrade from 1.3.0 to 1.4.0" - task "execute_release_1.4.0_tasks": [ - "active_storage:migrate_from_paperclip" + desc "Runs tasks needed to upgrade from 1.4.0 to 1.5.0" + task "execute_release_1.5.0_tasks": [ + "active_storage:remove_paperclip_compatibility_in_existing_attachments" ] end diff --git a/spec/controllers/proposals_controller_spec.rb b/spec/controllers/proposals_controller_spec.rb index ae586123b..05e1cc279 100644 --- a/spec/controllers/proposals_controller_spec.rb +++ b/spec/controllers/proposals_controller_spec.rb @@ -8,38 +8,4 @@ describe ProposalsController do expect { get :index }.to raise_exception(FeatureFlags::FeatureDisabled) end end - - describe "PUT update" do - let(:file) { Rails.root.join("spec/hacked") } - - before do - File.delete(file) if File.exist?(file) - InvisibleCaptcha.timestamp_enabled = false - end - - after { InvisibleCaptcha.timestamp_enabled = true } - - it "ignores malicious cached attachments with remote storages" do - allow_any_instance_of(Image).to receive(:filesystem_storage?).and_return(false) - user = create(:user) - proposal = create(:proposal, author: user) - sign_in user - - begin - put :update, params: { - id: proposal, - proposal: { - image_attributes: { - title: "Hacked!", - user_id: user.id, - cached_attachment: "| touch #{file}" - } - } - } - rescue StandardError - ensure - expect(file).not_to exist - end - end - end end diff --git a/spec/lib/tasks/active_storage_spec.rb b/spec/lib/tasks/active_storage_spec.rb index 2a8043556..9b2edc68d 100644 --- a/spec/lib/tasks/active_storage_spec.rb +++ b/spec/lib/tasks/active_storage_spec.rb @@ -1,90 +1,67 @@ require "rails_helper" describe "active storage tasks" do - describe "migrate_from_paperclip" do + describe "remove_paperclip_compatibility_in_existing_attachments" do let(:run_rake_task) do - Rake::Task["active_storage:migrate_from_paperclip"].reenable - Rake.application.invoke_task("active_storage:migrate_from_paperclip") + Rake::Task["active_storage:remove_paperclip_compatibility_in_existing_attachments"].reenable + Rake.application.invoke_task("active_storage:remove_paperclip_compatibility_in_existing_attachments") end - let(:storage_root) { ActiveStorage::Blob.service.root } - before { FileUtils.rm_rf storage_root } + it "updates old regular attachments" do + document = create(:document) + image = create(:image) + site_customization_image = create(:site_customization_image) - it "migrates records and attachments" do - document = build(:document, - attachment: nil, - paperclip_attachment: File.new("spec/fixtures/files/clippy.pdf")) - document.save(validate: false) + document.attachment.attachment.update_column(:name, "storage_attachment") + image.attachment.attachment.update_column(:name, "storage_attachment") + site_customization_image.image.attachment.update_column(:name, "storage_image") - expect(ActiveStorage::Attachment.count).to eq 0 - expect(ActiveStorage::Blob.count).to eq 0 - expect(test_storage_file_paths.count).to eq 0 + document.reload + image.reload + site_customization_image.reload + + expect(document.attachment.attachment).to be nil + expect(image.attachment.attachment).to be nil + expect(site_customization_image.image.attachment).to be nil run_rake_task document.reload + image.reload + site_customization_image.reload - expect(ActiveStorage::Attachment.count).to eq 1 - expect(ActiveStorage::Blob.count).to eq 1 - expect(document.storage_attachment.filename).to eq "clippy.pdf" - expect(test_storage_file_paths.count).to eq 1 - expect(storage_file_path(document)).to eq test_storage_file_paths.first + expect(document.attachment.attachment.name).to eq "attachment" + expect(image.attachment.attachment.name).to eq "attachment" + expect(site_customization_image.reload.image.attachment.name).to eq "image" end - it "migrates records with deleted files ignoring the files" do - document = build(:document, - attachment: nil, - paperclip_attachment: File.new("spec/fixtures/files/clippy.pdf")) - document.save(validate: false) - FileUtils.rm(document.attachment.path) + it "does not modify old ckeditor attachments" do + image = Ckeditor::Picture.create!(data: Rack::Test::UploadedFile.new("spec/fixtures/files/clippy.png")) + + expect(image.storage_data.attachment.name).to eq "storage_data" + + run_rake_task + image.reload + + expect(image.storage_data.attachment.name).to eq "storage_data" + end + + it "does not modify new regular attachments" do + document = create(:document) + image = create(:image) + site_customization_image = create(:site_customization_image) + + expect(document.attachment.attachment.name).to eq "attachment" + expect(image.attachment.attachment.name).to eq "attachment" + expect(site_customization_image.image.attachment.name).to eq "image" run_rake_task document.reload + image.reload + site_customization_image.reload - expect(ActiveStorage::Attachment.count).to eq 1 - expect(ActiveStorage::Blob.count).to eq 1 - expect(document.storage_attachment.filename).to eq "clippy.pdf" - expect(test_storage_file_paths.count).to eq 0 - end - - it "does not migrate already migrated records" do - document = create(:document, attachment: File.new("spec/fixtures/files/clippy.pdf")) - - migrated_file = test_storage_file_paths.first - attachment_id = document.storage_attachment.attachment.id - blob_id = document.storage_attachment.blob.id - - run_rake_task - document.reload - - expect(ActiveStorage::Attachment.count).to eq 1 - expect(ActiveStorage::Blob.count).to eq 1 - expect(document.storage_attachment.attachment.id).to eq attachment_id - expect(document.storage_attachment.blob.id).to eq blob_id - - expect(test_storage_file_paths.count).to eq 1 - expect(storage_file_path(document)).to eq migrated_file - expect(test_storage_file_paths.first).to eq migrated_file - end - - it "does not migrate files for deleted records" do - document = create(:document, attachment: File.new("spec/fixtures/files/clippy.pdf")) - FileUtils.rm storage_file_path(document) - Document.delete_all - - run_rake_task - - expect(ActiveStorage::Attachment.count).to eq 1 - expect(ActiveStorage::Blob.count).to eq 1 - expect(document.storage_attachment.filename).to eq "clippy.pdf" - expect(test_storage_file_paths.count).to eq 0 - end - - def test_storage_file_paths - Dir.glob("#{storage_root}/**/*").select { |file_or_folder| File.file?(file_or_folder) } - end - - def storage_file_path(record) - ActiveStorage::Blob.service.path_for(record.storage_attachment.blob.key) + expect(document.attachment.attachment.name).to eq "attachment" + expect(image.attachment.attachment.name).to eq "attachment" + expect(site_customization_image.reload.image.attachment.name).to eq "image" end end end diff --git a/spec/lib/tasks/files_spec.rb b/spec/lib/tasks/files_spec.rb index 454abe7be..4d55334bb 100644 --- a/spec/lib/tasks/files_spec.rb +++ b/spec/lib/tasks/files_spec.rb @@ -11,8 +11,8 @@ describe "files tasks" do image = build(:image) document = build(:document) - image.storage_attachment.blob.save! - document.storage_attachment.blob.save! + image.attachment.blob.save! + document.attachment.blob.save! travel_to(2.days.from_now) { run_rake_task } @@ -24,8 +24,8 @@ describe "files tasks" do image = build(:image) document = build(:document) - image.storage_attachment.blob.save! - document.storage_attachment.blob.save! + image.attachment.blob.save! + document.attachment.blob.save! travel_to(2.minutes.from_now) { run_rake_task } diff --git a/spec/models/direct_upload_spec.rb b/spec/models/direct_upload_spec.rb index 7f281cc22..815421180 100644 --- a/spec/models/direct_upload_spec.rb +++ b/spec/models/direct_upload_spec.rb @@ -40,8 +40,8 @@ describe DirectUpload do direct_upload.save_attachment expect(File.exist?(direct_upload.relation.file_path)).to be true - expect(direct_upload.relation.storage_attachment.blob).to be_persisted - expect(direct_upload.relation.storage_attachment.attachment).not_to be_persisted + expect(direct_upload.relation.attachment.blob).to be_persisted + expect(direct_upload.relation.attachment.attachment).not_to be_persisted end end end diff --git a/spec/models/document_spec.rb b/spec/models/document_spec.rb index 2f8cf65fe..af3294e9f 100644 --- a/spec/models/document_spec.rb +++ b/spec/models/document_spec.rb @@ -4,14 +4,11 @@ describe Document do it_behaves_like "document validations", "budget_investment_document" it_behaves_like "document validations", "proposal_document" - it "stores attachments with both Paperclip and Active Storage" do + it "stores attachments with Active Storage" do document = create(:document, attachment: File.new("spec/fixtures/files/clippy.pdf")) - expect(document.attachment).to exist - expect(document.attachment_file_name).to eq "clippy.pdf" - - expect(document.storage_attachment).to be_attached - expect(document.storage_attachment.filename).to eq "clippy.pdf" + expect(document.attachment).to be_attached + expect(document.attachment.filename).to eq "clippy.pdf" end context "scopes" do diff --git a/spec/models/image_spec.rb b/spec/models/image_spec.rb index d119c8138..da5b70d46 100644 --- a/spec/models/image_spec.rb +++ b/spec/models/image_spec.rb @@ -4,13 +4,10 @@ describe Image do it_behaves_like "image validations", "budget_investment_image" it_behaves_like "image validations", "proposal_image" - it "stores attachments with both Paperclip and Active Storage" do + it "stores attachments with Active Storage" do image = create(:image, attachment: File.new("spec/fixtures/files/clippy.jpg")) - expect(image.attachment).to exist - expect(image.attachment_file_name).to eq "clippy.jpg" - - expect(image.storage_attachment).to be_attached - expect(image.storage_attachment.filename).to eq "clippy.jpg" + expect(image.attachment).to be_attached + expect(image.attachment.filename).to eq "clippy.jpg" end end diff --git a/spec/models/site_customization/image_spec.rb b/spec/models/site_customization/image_spec.rb index ddd266d0e..c1bb77880 100644 --- a/spec/models/site_customization/image_spec.rb +++ b/spec/models/site_customization/image_spec.rb @@ -1,15 +1,12 @@ require "rails_helper" describe SiteCustomization::Image do - it "stores images with both Paperclip and Active Storage" do + it "stores images with Active Storage" do image = create(:site_customization_image, name: "map", image: File.new("spec/fixtures/files/custom_map.jpg")) - expect(image.image).to exist - expect(image.image_file_name).to eq "custom_map.jpg" - - expect(image.storage_image).to be_attached - expect(image.storage_image.filename).to eq "custom_map.jpg" + expect(image.image).to be_attached + expect(image.image.filename).to eq "custom_map.jpg" end describe "logo" do diff --git a/spec/system/admin/site_customization/documents_spec.rb b/spec/system/admin/site_customization/documents_spec.rb index fe2fe332a..6a2063299 100644 --- a/spec/system/admin/site_customization/documents_spec.rb +++ b/spec/system/admin/site_customization/documents_spec.rb @@ -18,7 +18,7 @@ describe "Documents", :admin do 1.times { create(:document) } document = Document.first - url = polymorphic_path(document.storage_attachment) + url = polymorphic_path(document.attachment) visit admin_site_customization_documents_path