Rails Paperclip как удалить вложение?

84

Я использую Paperclip (w / Amazon s3) на Rails 3. Я хочу удалить существующее вложение, не заменяя его, с помощью действия обновления.

Я нашел здесь только один пример и не смог заставить его работать, он просто не удалялся, и в журналах не было ничего, чтобы сказать, почему. Я хотел сделать что-то вроде этого в форме:

<%- unless @page.new_record? || !@page.image? -%>
    <%= f.check_box :image_delete, :label => 'Delete Image' %>
<%- end -%>

(страница - это имя модели, изображение - это имя атрибута, содержащего вложение)

Но как мне обнаружить этот флажок и, что более важно, как удалить изображение? Я ценю любую помощь!

Джозеф
источник

Ответы:

104

Во-первых, когда вы создаете check_box в form_for (который, похоже, и есть), тогда форма по умолчанию должна отправлять: image_delete как «1», если отмечено и «0», если не отмечено. Объявление метода выглядит так:

def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")

Это показывает, что вы можете назначить другие значения, если хотите, но это, конечно, необязательно.

Во-вторых, призыв вручную удалить вложение без удаления экземпляра модели, к которому оно прикреплено:

@page.image.destroy #Will remove the attachment and save the model
@page.image.clear #Will queue the attachment to be deleted

И чтобы выполнить свой способ удаления изображений с помощью флажка, возможно, добавьте что-то вроде этого в свою модель страницы:

class Page < ActiveRecord::Base
  has_attached_file :image

  before_save :destroy_image?

  def image_delete
    @image_delete ||= "0"
  end

  def image_delete=(value)
    @image_delete = value
  end

private
  def destroy_image?
    self.image.clear if @image_delete == "1"
  end
end

Таким образом, когда вы создаете форму и добавляете флажок: image_delete, она загружает значение по умолчанию «0» из экземпляра User. И если это поле отмечено, тогда контроллер обновит image_delete до «1», и когда пользователь будет сохранен, он проверит, нужно ли удалить изображение.

DanneManne
источник
В этом примере относится ли Page # image к другой модели has_attached_file, или у страницы есть вложение с именем image?
Джон Башир
@page - это переменная модели, имеющая_attached_file: image, но я, кажется, почему-то назвал модель User. Я изменю и обновлю, чтобы уточнить.
DanneManne 06
Хорошо, это имеет больше смысла :)
Джон Бачир
Я не понимаю, почему вы не просто выполняете там self.image.destroy - удаляет ли основной файл, но сохраняет метаинформацию об изображении в модели страницы? Зачем вам это нужно? (и не похоже, что это то, что хочет сделать
задающий
11
Этот подход также сработал для меня ... но я столкнулся с одной проблемой ... если пользователь проверяет флажок image_delete и одновременно добавляет новое изображение в форму, тогда старое изображение удаляется, а новое изображение не сохраняется . Я решил это, изменив условие на метод self.image.clear if @image_delete == "1" and !image.dirty?indestroy_image?
Зишан
97

has_attached_file :asset

=>

    attr_accessor :delete_asset
    before_validation { asset.clear if delete_asset == '1' }

Не нужно уничтожать актив, Скрепка это сделает.

По форме form.check_box(:delete_asset)хватит.

Бенуа Б.
источник
3
Это работает, и это проще, чем ответ @DanneManne ИМХО. Очень хорошо! :)
MetalElf0
Как бы вы написали для этого спецификацию?
Hengjie
1
Благодаря ! Чтобы помочь мне еще больше сократить это до: has_attached_file :asset has_destroyable_file :asset Я создал инициализатор для добавления в config/initializers/ gist.github.com/3954054
Sunny
2
Я обнаружил проблему с этим методом по крайней мере через accept_nested_attributes. before_validation не запускается при вложенном сохранении, если никакие другие атрибуты не были изменены. Смотрите мой ответ ниже для решения
Пол Одеон
4
@SurgePedroza Я считаю, что вам нужно разрешить параметр: delete_asset, см. Guides.rubyonrails.org/…
sman591 05
12

Это ответ Бенуа, но завернутый в модуль и покрывающий крайний случай моделей вложенных атрибутов, где галочка уничтожения - единственное, что изменилось в модели.

Он будет применяться ко всем насадкам модели.

# This needs to be included after all has_attached_file statements in a class
module DeletableAttachment
  extend ActiveSupport::Concern

  included do
    attachment_definitions.keys.each do |name|

      attr_accessor :"delete_#{name}"

      before_validation { send(name).clear if send("delete_#{name}") == '1' }

      define_method :"delete_#{name}=" do |value|
        instance_variable_set :"@delete_#{name}", value
        send("#{name}_file_name_will_change!")
      end

    end
  end

end
Пол Одеон
источник
1
Не знаю, почему этому не уделяется больше внимания. attachment_definitionsтолько что спас мне жизнь.
okay56k
Хотя нужна и эта строчка:attr_accessible :"delete_#{name}"
okay56k
2
Приведенный выше пример должен быть в папке с вашими проблемами или моделью. В модели, в которой вы хотите, просто добавьте строку include DeletableAttachmentпод любыми has_attached_fileутверждениями
Пол Одеон
2
В rails3 вам также понадобится attr_accessible: "delete _ # {name}"
Матеу
1
Не забудьте разрешить, :delete_<your_attribute>если вы используете
строгие
5

не забудьте добавить это и в свою модель страницы:

attr_accessible :image_delete
Гленн МакВ
источник
1

Модифицированная версия решения Пола для поддержки настраиваемых атрибутов Rails 5. Я просто хотел бы, чтобы был способ включить модуль в начало файла, перед has_attached_fileопределениями.

module Mixins
  module PaperclipRemover

    extend ActiveSupport::Concern

    included do
      attachment_definitions.keys.each do |name|

        attribute :"remove_#{name}", :boolean

        before_validation do
          self.send("#{name}=", nil) if send("remove_#{name}?")
        end

      end
    end

  end

end
JBlake
источник
0

Этого удалось добиться с меньшим количеством кода, просто реализовав delete_attachmentна стороне модели:

class MyModel < ApplicationRecord
  has_attached_file :image

  def image_delete=(other)
    self.image = nil if other == "1" or other == true
  end
end
Stwienert
источник