Рельсы и скрепка, удалите запись, но не удаляйте вложение - PullRequest
5 голосов
/ 16 мая 2011

Я использую рельсы и скрепку для сохранения изображений обычным способом.

Когда запись с вложением уничтожается, вложение также удаляется из файловой системы.

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

Мне было интересно,Кто-нибудь знал, как это сделать.

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

Приветствия.

Ответы [ 6 ]

3 голосов
/ 16 мая 2011

Вы можете взглянуть на то, как Attachment#assign (вызывается, когда вы делаете object.attachment = new_attachment) реализовано в скрепке.По сути, он немного настраивается, затем вызывает Attachment#clear, затем сохраняет новый файл.

Attachment # clear помещает старый файл в очередь удаления, которая обрабатывается при повторном вызове save, что выwant - это просто избежать вызова clear, что можно сделать, написав новый метод assign, который пропускает эту строку, или мартышкой пропатчив #clear, чтобы он стал no-op.Теоретически, вы можете просто сделать это в тех случаях, когда вы хотите, чтобы это произошло, но мне кажется, что вы можете сделать это для всего проекта.

Или вы можете очистить переменную экземпляра, содержащую очередь обработки.Эта переменная не имеет метода доступа, но это должно быть тривиально: instance_variable_get

1 голос
/ 03 июля 2015

Для меня переопределение метода Paperclip::Attachment#clear не сработало.Я должен был переопределить Paperclip::Attachment#queue_all_for_delete.

Как сказал Алекс Фальке, у Paperclip есть опция :preserve_files, поэтому, очевидно, что если вы хотите сохранить все вложения, вы бы использовали их вместо переопределения.

Если у вас есть особый случай, переопределение #queue_all_for_delete - это путь, но вам придется делать это выборочно.Исправление обезьян является глобальным, так что это не лучший подход.Я пытался использовать уточнения, чтобы ограничить область исправления обезьяны, но лексическая область видимости не очень хорошо подходила для моего варианта использования.

Итак, я закончил с этим модулем, который внедряет себя в путь поиска метода и выборочно определяет или отменяет определение переопределения no-op для #queue_all_for_delete:

module PaperclipKeepAttachment
  def self.with_patch
    patch
    add_override
    yield
  ensure
    remove_override
  end

  def self.patch
    me = self
    Paperclip::Attachment.class_eval{ prepend me } unless Paperclip::Attachment.ancestors.include?(me)
  end

  def self.add_override
    define_method(:queue_all_for_delete) do
      # no-op
    end
  end

  def self.remove_override
    remove_method(:queue_all_for_delete)
  end
end

С его помощью вы можетесделать что-то вроде:

PaperclipKeepAttachment.with_patch do 
  # The record will be destroyed but the attachment kept intact
  first_record.destroy
end

# The record will be destroyed and the attachment removed
second_record.destroy
1 голос
/ 28 мая 2014

Самоцвет позволяет сделать мягкое удаление:

(из скрепка )

Сохранение файлов для Soft-Delete

Опция доступна для сохранения вложений, чтобы хорошо играть с мягко удаленными моделями. (act_as_paranoid, паранойя и т. д.)

has_attached_file :some_attachment, {
    :preserve_files => "true",
}

Это предотвратит уничтожение some_attachment при разрушении модели, поэтому оно будет существовать, когда объект будет восстановлен позже.

1 голос
/ 12 апреля 2013

Может быть, немного не по теме:

В случае, когда вложение сохраняется на S3 - вы можете просто переопределить метод has_attached_file и передать только имя вложения без каких-либо опций. Скрепка будет думать в этом случае, что файл хранится в файловой системе и просто ничего не удалит. Также не исключение.

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

1 голос
/ 16 мая 2011

Итак, вопрос в том, что происходит?Вы пытаетесь осуществить отмену, чтобы кто-то мог удалить, а затем восстановить?

Я бы поспорил, что ваше решение должно иметь дело с флагом очистки и последующим удалением в пакетном задании ночью, если флаг очистки имеет значение trueНе повлияет на производительность, пока все получает для записей, где clear = false с индексом.У вопроса просто есть ощущение "неправильности" в решении этого вопроса.Просто предлагая другую точку зрения.

1 голос
/ 16 мая 2011

Обнуление полей базы данных, которые генерирует paperclip (file_name, content_type, file_size), не сохранит файл. Метод destroy по-прежнему будет указывать его через индекс.

Попробуйте изменить идентификатор на случайное число (например, 999898), прежде чем уничтожить запись. Если он выдает исключение, также обнуляйте поля. Таким образом, запись больше не будет указывать на файл и останется, когда запись будет уничтожена.

...