Rails4:检查删除图像时没有使用carrierwave上传的图像

时间:2014-09-13 02:17:03

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

我想要做的是让用户选择至少一张图片(最多3张图片)并在\ views \ shared \ _article_form.html.erb中输入f.text_area :content
我在\ models \ article.rb中添加了自定义验证check_for_at_least_image 它仅在create操作中有效(仅显示错误消息),但它在update操作中无效。
如何在update操作中检查无图像并显示错误消息。

article有很多photo

日志如下。

\ log / development.log

新创建时无图像(错误消息按我的预期显示)

Started POST "/articles" for 127.0.0.1 at 2014-09-13 10:40:49 +0900
Processing by ArticlesController#create as HTML
  Parameters: {"utf8"=>"笨・, "authenticity_token"=>"xxxx=", "article"=>{"category_id"=>"1379", "photos_attributes"=>{"0"=>{"article_id"=>""}, "1"=>{"article_id"=>""}, "2"=>{"article_id"=>""}}, "content"=>"test"}, "commit"=>"逋サ骭イ縺吶k"}
  [1m[35mUser Load (0.0ms)[0m  SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'xxxx' LIMIT 1
  [1m[36m (0.0ms)[0m  [1mbegin transaction[0m
  [1m[35m (0.0ms)[0m  rollback transaction
  [1m[36mCategory Load (1.0ms)[0m  [1mSELECT "categories".* FROM "categories" WHERE "categories"."id" = ? LIMIT 1[0m  [["id", 1379]]
  Rendered shared/_error_messages.html.erb (1.0ms)
  Rendered shared/_article_form.html.erb (8.0ms)
  Rendered articles/new.html.erb within layouts/application (10.0ms)
  Rendered layouts/_header.html.erb (1.0ms)
  Rendered layouts/_footer.html.erb (0.0ms)
Completed 200 OK in 63ms (Views: 51.0ms | ActiveRecord: 1.0ms)

删除所有(三张)图片(未显示错误讯息)

Started PATCH "/articles/40" for 127.0.0.1 at 2014-09-13 11:10:00 +0900
Processing by ArticlesController#update as HTML
  Parameters: {"utf8"=>"笨・, "authenticity_token"=>"xxxx=", "article"=>{"category_id"=>"1379", "photos_attributes"=>{"0"=>{"article_id"=>"40", "_destroy"=>"1", "id"=>"132"}, "1"=>{"article_id"=>"40", "_destroy"=>"1", "id"=>"133"}, "2"=>{"article_id"=>"40", "_destroy"=>"1", "id"=>"134"}}, "content"=>"test"}, "commit"=>"譖エ譁ー縺吶k", "id"=>"40"}
  [1m[35mUser Load (0.0ms)[0m  SELECT "users".* FROM "users" WHERE "users"."remember_token" = 'xxxx' LIMIT 1
  [1m[36mArticle Load (0.0ms)[0m  [1mSELECT "articles".* FROM "articles" WHERE "articles"."user_id" = ? AND "articles"."id" = 40 ORDER BY created_at DESC LIMIT 1[0m  [["user_id", 1]]
  [1m[35mArticle Load (1.0ms)[0m  SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? ORDER BY created_at DESC LIMIT 1  [["id", "40"]]
  [1m[36m (0.0ms)[0m  [1mbegin transaction[0m
  [1m[35mPhoto Load (1.0ms)[0m  SELECT "photos".* FROM "photos" WHERE "photos"."article_id" = ? AND "photos"."id" IN (132, 133, 134)  [["article_id", 40]]
  [1m[36m (0.0ms)[0m  [1mSELECT COUNT(*) FROM "photos" WHERE "photos"."article_id" = ?[0m  [["article_id", 40]]
  [1m[35mSQL (1.0ms)[0m  DELETE FROM "photos" WHERE "photos"."id" = ?  [["id", 132]]
  [1m[36mSQL (0.0ms)[0m  [1mDELETE FROM "photos" WHERE "photos"."id" = ?[0m  [["id", 133]]
  [1m[35mSQL (0.0ms)[0m  DELETE FROM "photos" WHERE "photos"."id" = ?  [["id", 134]]
  [1m[36m (4.0ms)[0m  [1mcommit transaction[0m
Redirected to http://localhost:3000/users/1
Completed 302 Found in 26ms (ActiveRecord: 7.0ms)

照片表

sqlite> .schema photos
CREATE TABLE "photos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "articl_id" integer, "image" varchar(255), "created_at" datetime, "updated_at" datetim);

\模型\ article.rb

# encoding: utf-8
class Article < ActiveRecord::Base
    belongs_to :user
    belongs_to :category
    has_many :photos, dependent: :destroy
    accepts_nested_attributes_for :photos, reject_if: :all_blank, allow_destroy: true
    default_scope -> { order('created_at DESC') }
    validates :content, presence: true, length: { maximum: 140 }
    validates :user_id, presence: true
    validates :category_id, presence: true
    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...") if self.photos.size <= 0
    end

end

\模型\ photo.rb

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

\视图\物品\ edit.html.erb

<div class="row">
  <div class="span8">
        <%= render 'shared/article_form' %>
  </div>
</div>

\ view \ shared \ _article_form.html.erb

<%= form_for(@article) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.hidden_field :category_id %>
    <%= 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>article:<%= @article.id %></p>
        <p>photo:<%= p.object.id %></p>
        <%= p.hidden_field :image_cache if p.object.image_cache %>
        <label><%= p.check_box :_destroy %>delete</label>
      <% end %>
      <%= p.file_field :image %>
      </div>
    <% end %>
    <%= f.text_area :content, placeholder: "Enter content..." %>
  </div>
  <%= f.submit class: "btn btn-large btn-primary" %>
<% end %>

\控制器\ articles_controller.rb

class ArticlesController < ApplicationController

  before_action :signed_in_user, only: [:create, :destroy]
  before_action :correct_user,   only: [:update, :destroy]
.
.
  def new
    @article = Article.new
    @category  = Category.find(params[:category])
    @article.category_id = @category.id
    3.times { @article.photos.build }
  end

  def create
    @article = current_user.articles.build(article_params)
    if @article.save
      flash[:success] = "article created!"
      redirect_to current_user #root_url
    else
        @article.build_images
       render 'new'
    end
  end
.
.
  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
    @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

1 个答案:

答案 0 :(得分:0)

只是查看了你的问题,并且 认为可能是你的验证在儿童对象的破坏性调用之前运行 并进行了一些搜索并找到了{{3}看起来我认为在毁灭之前运行验证是正确的。只是发布与您的问题相关的指针

  

这里的问题是在验证父对象之后,accept_nested_attributes_for为子对象调用destroy。因此用户可以删除图像。当然,稍后,当用户尝试编辑文章时,他/她将收到错误 - “选择至少一个图像。”。

<强>修正:

accepts_nested_attributes_for :photos, reject_if: proc { |attributes| attributes['image'].blank? } , allow_destroy: true  #as discussed in your other question you have to use proc to solve your update problem

validate :check_for_at_least_image

def check_for_at_least_image
  errors.add(:image, "select...") if photos.reject(&:marked_for_destruction?).size <= 0
end