Rails4:如何同时删除图像并在DB中记录?

时间:2014-08-25 12:34:41

标签: ruby-on-rails ruby-on-rails-4 carrierwave

如何在销毁图像的同时删除数据库中的记录?
尽管图片已被删除,但在_article_form.html.erb中提交勾选<%= p.check_box :_destroy %>后,记录仍保留在数据库中。

更新
我做的是如下;
1.我上传了3个文件。例如,p.object.id分别为1,2和3。它奏效了。
2.我勾选了1个文件(p.object.id为1)进行销毁并提交。有效。 DB和图像中的记录都被删除了。显示其余图像(2个文件) 3.我勾选了1个文件(p.object.id为2)进行销毁并提交。它不起作用。数据库中的记录和图片(p.object.id为2)已删除,但由于某种原因,新记录(p.object.id 4 )已插入数据库...

\上传\ image_uploader.rb

class ImageUploader < CarrierWave::Uploader::Base
    .
    .
  include CarrierWave::RMagick
  storage :file
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
    .
    .

\模型\ article.rb

class Article < ActiveRecord::Base
    .
    .
    has_many :photos, dependent: :destroy
    accepts_nested_attributes_for :photos, reject_if: :all_blank, allow_destroy: true
    validates :content, presence: true, length: { maximum: 140 }
    validate :check_for_at_least_image
    .
    .
    def build_images
      (3 - self.photos.size).times {self.photos.build}
    end

    def check_for_at_least_image
      errors.add(:image, "select at least one") if self.photos.size <= 0
    end

end

\模型\ photo.rb

class Photo < ActiveRecord::Base
    belongs_to :article
    mount_uploader :image, ImageUploader
end

\控制器\ articles_controller.rb

class ArticlesController < ApplicationController

.
.
  def edit
    @article = Article.find(params[:id])
    @article.build_images
  end

  def update
    @article = Article.find(params[:id])
    if @article.update(article_params)
      redirect_to current_user
    else
      render 'edit'
    end
  end

  def destroy #This is used for destroying @article, NOT photo
    @article.destroy
    redirect_to root_url
  end

  private

    def article_params
      params.require(:article).permit(:content, :category_id, photos_attributes: [:id, :article_id, :image, :image_cache, :_destroy])
    end

.
.
end

\ view \ shared \ _article_form.html.erb

<%= form_for(@article) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.fields_for :photos do |p| %>
      <%= p.hidden_field :article_id %>
      <div class="photo">
      <% if p.object.image and p.object.image.file %>
        <%= image_tag p.object.image.thumb.url %>
        <%= p.hidden_field :image_cache if p.object.image_cache %>
        <label><%= p.check_box :_destroy %>delete</label> #tick this check box
      <% end %>
      <%= p.file_field :image %>
      </div>
    <% end %>
    <%= f.text_area :content, placeholder: "enter..." %>
  </div>
  <%= f.submit class: "btn btn-large btn-primary" %>
<% end %>

3 个答案:

答案 0 :(得分:1)

如果你想从db和view中删除数据,那么我推荐这种方式...不使用accept_nested_attributes_for只能在保存父对象后才能工作,并且会使用{{1属性设置为true / 1。

<强> 1。通过传递object.id给你的元素一个唯一的id 2.使用此object.id选择元素并使用js.erb将其删除,并在成功的同一页面上使用远程调用/ ajax

==========第一种方法(没有accept_nested_attributes-for)======================
---------使用远程方法调用(不设置_destroy)----------------

_destroy
在articles_controller.rb中

<%= form_for(@article) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.fields_for :photos do |p| %>
      <%= p.hidden_field :article_id %>
      ##here i added id field which i need to recognize using id 
      <div class="photo" id="photo_<%= p.id %>">
      <% if p.object.image and p.object.image.file %>
        <%= image_tag p.object.image.thumb.url %>
        <%= p.hidden_field :image_cache if p.object.image_cache %>
        ##instead of checkbox,use link_to
        ##<label><%= p.check_box :_destroy %>delete</label> #tick this check box
         <%= link_to "Delete", article_path(p),{:method => :delete,:remote=>true%>
        </td>
      <% end %>
      <%= p.file_field :image %>
      </div>
    <% end %>
    <%= f.text_area :content, placeholder: "enter..." %>
  </div>
  <%= f.submit class: "btn btn-large btn-primary" %>
<% end %>
在destroy.js.erb

  def destroy
  ##first remove from db and then from view using id passed 
   @article=Artice.find params[:id]
    @audio.destroy
          respond_to do |format|
           format.js 
         end
  end

==========第二种方法(使用接受嵌套属性)========================= =
---------使用jquery删除图像并将对象标记为破坏,方法是将_destroy设置为1(使用_destroy将其设置为1)-------

您视图中的

##delete the image from your view using p.id with a slideup animation(if needed)
$("#photo_<%= params[:id] %").slideUp("slow", function() { $('#photo_<%= params[:id]%>').remove();});

你的jquery

<%= form_for(@article) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.fields_for :photos do |p| %>
      <%= p.hidden_field :article_id %>
      <div class="photo">
      <% if p.object.image and p.object.image.file %>
        <%= image_tag p.object.image.thumb.url %>
        <%= p.hidden_field :image_cache if p.object.image_cache %>
        ##on click of checkbox,set _destroy to 1,which will get deleted by parent
        ##when parent is updated/saved
        <label><%= p.check_box :_destroy :class => 'delete_member', :p_id => p.id %>
          delete</label> #tick this check box

        </td>
      <% end %>
      <%= p.file_field :image %>
      </div>
    <% end %>
    <%= f.text_area :content, placeholder: "enter..." %>
  </div>
  <%= f.submit class: "btn btn-large btn-primary" %>
<% end %>

因此,在将_destroy设置为1后,记录也将被rails删除,因为我们已使用_destroy属性将其标记为要销毁

答案 1 :(得分:0)

dependent: :destroy如果你破坏了一篇应该破坏照片的文章应该可行。如果这有问题,您可以随时创建回调“before_destroy”或“after_destroy”。

答案 2 :(得分:0)

您可以尝试将_destroy重命名为remove_fileremove_<mounted-point>

如果要手动删除文件,可以调用remove_<mounted-point>!,然后保存对象(或在回调中执行)。

photo.remove_<mounted-point>!
photo.save