Railsペーパークリップ添付ファイルを削除する方法は?


84

私が使用していますペーパークリップon Railsの(/ Amazon S3のワット)を3.私は、既存の添付ファイルを削除することを交換することなく、更新アクションを使用して。

私はここでこれの1つの例を見つけただけで、それを機能させることができませんでした。削除されず、ログには理由を示すものが何もありませんでした。フォームで次のようなことをしたかったのです。

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

(ページはモデルの名前、画像は添付ファイルを保持する属性名です)

しかし、そのチェックボックスを検出するにはどうすればよいですか、さらに重要なことに、画像を削除するにはどうすればよいですか?助けてくれてありがとう!

回答:


104

まず、form_forでcheck_boxを作成すると(現在のように見えます)、フォームはデフォルトで: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」に更新し、ユーザーが保存されると、イメージが削除されるかどうかをチェックします。


この例では、Page#imageはhas_attached_file、imageという名前の添付ファイルがある別のモデルを参照していますか?
John Bachir 2011年

@pageはhas_attached_file:imageのモデル変数ですが、何らかの理由でモデルにUserという名前を付けたようです。明確にするために変更および更新します。
DanneManne 2011年

わかりました、それはもっと理にかなっています:)
John Bachir 2011年

そこでself.image.destroyを実行しない理由がわかりません。基になるファイルをクリアで削除しますが、ページモデルの画像に関するメタ情報を維持しますか?なぜあなたはこれをしたいのですか?(そして、それは質問者がやりたいことではないようです)
John Bachir 2011年

11
このアプローチも私にはうまくいきました...しかし私は1つの問題に直面しました...ユーザーがimage_deleteチェックボックスをチェックし、同時にフォームに新しい画像を追加すると、古い画像が削除され、新しい画像は保存されません。条件をself.image.clear if @image_delete == "1" and !image.dirty?indestroy_image?メソッドに変更することでこれを解決しました
Zeeshan 2011

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 2012年

このための仕様をどのように記述しますか?
Hengjie 2012

1
ありがとう!これをさらにスリムhas_attached_file :asset has_destroyable_file :asset 化するために、config/initializers/ 次の
Sunny

2
少なくともaccepts_nested_attributesを介して、このメソッドに問題があることがわかりました。他の属性が変更されていない場合、before_validationはネストされた保存でトリガーされません。解決策については、以下の私の回答を参照してください
Paul Odeon

4
@SurgePedrozaパラメータ:delete_assetを許可する必要があると思います。guides.rubyonrails.org/を参照してください
sman591

12

これはBenoitの答えですが、モジュールにラップされており、モデルで変更されたのは破棄ティックボックスだけであるネストされた属性モデルのエッジケースをカバーしています。

モデル上のすべてのアタッチメントに適用されます。

# 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 2014年

にもかかわらず、あまりにもこのラインを必要とします:attr_accessible :"delete_#{name}"
okay56k

2
上記の例は、懸念事項またはモデルフォルダにあるはずです。必要なモデルでinclude DeletableAttachmenthas_attached_fileステートメントの下に行を追加するだけです
Paul Odeon

2
rails3では、attr_accessible: "delete _#{name}"も必要になります
Mateu

1
:delete_<your_attribute>コントローラで強力なパラメータを使用している場合は、許可することを忘れないでください
ivanxuu 2015年

5

これをページモデルにも追加することを忘れないでください。

attr_accessible :image_delete

1

Rails5カスタム属性をサポートするためのPaulのソリューションの修正バージョン。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

delete_attachmentモデル側にを実装するだけで、より少ないコードでこれを実現できました。

class MyModel < ApplicationRecord
  has_attached_file :image

  def image_delete=(other)
    self.image = nil if other == "1" or other == true
  end
end
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.