Як видалити вкладення?


84

Я використовую скріпку (w / Amazon s3) на Rails 3. Я хочу видалити існуюче вкладення, не замінюючи його за допомогою дії оновлення.

Я знайшов тут лише один приклад цього, і не зміг змусити це працювати, він просто не видалявся, і в журналах не було нічого сказати, чому. Я хотів зробити щось подібне у формі:

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

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

Але як мені визначити цей прапорець і, що ще важливіше, як видалити зображення? Я вдячний за будь-яку допомогу!

Відповіді:


104

По-перше, коли ви створюєте прапорець у полі 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" з екземпляра користувача. І якщо це поле встановлено, тоді контролер оновить image_delete до "1", а коли Користувач буде збережений, він перевірить, чи слід видалити зображення.


У цьому прикладі зображення Сторінка # відноситься до іншої моделі, яка has_attached_fileмає вкладене сторінку, з назвою зображення?
Джон Бахір,

@page - це змінна моделі, яка has_attached_file: image, але, здається, я з якоїсь причини назвав модель User. Зміню і оновлю, щоб уточнити.
DanneManne

Гаразд, це має більше сенсу :)
Джон Бахір

Я не розумію, чому ви просто не робите там self.image.destroy - чи видаляє базовий файл, але зберігає метаінформацію про зображення в моделі сторінки? Чому ви хочете це зробити? (і, схоже, це не те, що хоче поставити запитувач)
Джон Бахір

11
Цей підхід також спрацював для мене ... але я зіткнувся з однією проблемою ... якщо користувач установить прапорець image_delete, а також одночасно додасть нове зображення у форму, то старе зображення буде видалено, а нове зображення не збережено . Я вирішив це, змінивши умову на self.image.clear if @image_delete == "1" and !image.dirty?in in destroy_image?method
Zeeshan

97

has_attached_file :asset

=>

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

Не потрібно знищувати активи, це зробить скріпка.

У формі form.check_box(:delete_asset)буде досить.


3
Це працює, і це простіше, ніж відповідь @DanneManne IMHO. Дуже добре! :)
MetalElf0

Як би ви написали специфікацію для цього?
Hengjie

1
Дякую ! Щоб допомогти мені ще більше це зменшити: has_attached_file :asset has_destroyable_file :asset я створив ініціалізатор для додавання до config/initializers/ gist.github.com/3954054
Сонячний

2
Я виявив проблему з цим методом щонайменше через acceptpts_nested_attributes. before_validation не запускається при вкладеному збереженні, якщо жоден інший атрибут не змінено. Дивіться мою відповідь нижче - рішення
Пол Одеон,

4
@SurgePedroza Я вважаю, що вам потрібно дозволити параметр: delete_asset, див. Guides.rubyonrails.org/…
змен591

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висловлюваннями
Paul Odeon,

2
У rails3 вам знадобиться attr_accessible: "delete _ # {name}" також
Mateu

1
Не забудьте дозволити, :delete_<your_attribute>якщо ви використовуєте сильні параметри у своєму контролері
ivanxuu,


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

0

Домігся цього з меншим кодом, просто застосувавши a delete_attachmentна стороні моделі.

class MyModel < ApplicationRecord
  has_attached_file :image

  def image_delete=(other)
    self.image = nil if other == "1" or other == true
  end
end
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.