即使验证失败,Active Storage仍会检测到附件

问题描述 投票:0回答:1

这是已经存在了一段时间的问题,直到今天,我仍然没有找到解决方案。我已经看到了一些类似的问题,但并不太了解我遇到的问题。

自从Rails 5推出以来,我一直在体验Rails Active Storage,但是由于这个特殊问题,它从未在生产中实际使用过。 Rails 6发布时解决的主要问题是,如果您对文件附件实施了任何验证,则记录将不会保存,但附件(blob)仍会保存,并且您的验证是基于内容类型的(确保它是JPEG图像),那么您最终得到了无效的附件(例如,如果您上传了文本文件)。如果您尝试使用例如image_tag来“显示”此附件,则会导致问题。 Rails 6仅通过将记录实际保存到数据库中时才保存附件来解决此问题。这对我来说只解决了一半问题。

这是我仍在经历的问题,尚未找到解决方案。

假设您有一个非常基本的设置。具有名称,电子邮件和附加头像的Person模型

Class Person < ApplicationRecord
  has_one_attached :avatar
  #Check that image type is jpg or png
  validate :check_image_type

  #Remove avatar flag needed for form
  attr_accessor :remove_avatar

  #purge picture if remove picture flag was ticked on form
  after_save :purge_avatar, if: :purge_requested?

  #Returns a thumbnail version of the property picture
  def thumbnail
    return self.avatar.variant(resize:'100x100').processed 
  end

  private 
    #Validates the image type being uploaded
    def check_image_type
      if avatar.attached? && !avatar.content_type.in?(%("image/jpeg image/png"))
        errors.add(:avatar, "Invalid Avatar Format")
      end
    end

    #Was a purge of the picture requested 
    def purge_requested?
      remove_avatar == "1"
    end

    def purge_avatar
      avatar.purge_later
    end
end 

您可以在上面的代码中看到,此人有一个附加的头像。保存后,我们将验证图像类型,以确保它是jpep或png;否则,我们仅向记录添加错误,这将阻止记录被保存。

这里是控制器代码(我省略了索引,编辑,更新和销毁操作)

class PeopleController < ApplicationController
  before_action :set_person, only: [:show, :edit, :update, :destroy]

  def new
    @person = Person.new
  end

  def create
    @person = Person.new(person_params)

    respond_to do |format|
      if @person.save
        format.html { redirect_to @person, notice: 'Person was successfully created.' }
        format.json { render :show, status: :created, location: @person }
      else
        format.html { render :new }
        format.json { render json: @person.errors, status: :unprocessable_entity }
      end
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_person
      @person = Person.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def person_params
      params.require(:person).permit(:name, :email, :avatar, :remove_avatar)
    end
end

然后在表单中,显示化身是否存在于表单顶部,然后让用户创建/编辑信息并根据需要选择另一个化身。

<%= form_with(model: person, local: true) do |form| %>
  <% if person.errors.any? %>
    <div id="error_explanation">
      <h2>
        <%= pluralize(person.errors.count, "error") %> prohibited this person from being saved:
      </h2>

      <ul>
        <% person.errors.full_messages.each do |message| %>
          <li><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>
  <!-- Display avatar if one attach -->
  <%if person.avatar.attached?%>
    <%=image_tag(person.avatar)%>
    Remove <%=form.check_box :remove_avatar%>
  <%end%>

  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <div class="field">
    <%= form.label :email %>
    <%= form.text_field :email %>
  </div>

  <!-- Select Picture -->
  <div class = "field">
    <%=form.label :avatar %>
    <%= form.file_field :avatar, accept: 'image/*'%>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

预期的行为是

  • [创建新人时,不显示任何化身(有效)
  • 通过选择适当的文件类型(jpg或png),您可以保存人物(有效)
  • 通过选择错误的文件类型,您无法保存此人,并且可以选择另一个文件(不起作用)

发生的情况是,您选择了错误的文件类型,它的确阻止了记录的保存,这很好,但是它仍然“看到”了非持久记录上的附件。因此,尽管在create动作上最初显示表单时没有显示化身,但是在验证失败后重新呈现表单时会显示“空”化身。这是由于附上的吗?即使记录上没有附件(因为它被拒绝),该方法也返回true。

拥有空白头像看起来有点时髦,它看起来像是链接断开的图片。但是,如果要对化身本身进行任何操作,例如Person类中的缩略图方法,则会生成以下错误:ActiveStorage :: InvariableError

这是由于附件?属性为true且头像属性有效,但没有关联的Blob(图片)。因此,尝试将其调整为缩略图大小会失败,并显示错误。

我正在尝试找到一种方法来“清除”或重置头像和/或已附加的头像?验证阻止记录保存时的属性。在内部,Rails会执行应做的工作(不保存文件,如果有的话,则不保存当前文件)。

但是表单上显示的内容(如果显示化身)势必会混淆用户,尤其是如果用户在选择新的化身之前拥有化身。如果您选择了一个无效的头像,并且表单拒绝了它,则在重新渲染时,您的初始头像将不会显示,并会替换为该图片损坏的链接图标。这可能会使用户感到困惑,以为他们的以前的头像已被擦除,而事实并非如此。在这一点上,我不确定在不深入研究活动存储胆量的情况下如何解决此问题(我现在不打算这样做)。

我试图打电话给我自己清除或为化身属性分配null,但这没用

def check_image_type
  if avatar.attached? && !avatar.content_type.in?(%("image/jpeg image/png"))
    errors.add(:avatar, "Invalid Avatar Format")
    avatar.purge    <---- Not working
    avatar = nil <--- Not working
    avatar = '' <--- Not working
  end
end
ruby-on-rails ruby rails-activestorage ruby-on-rails-6
1个回答
0
投票

为了防止错误,您可以使用persisted?

<% if person.avatar.attached? && person.avatar.persisted? %>
  <%= image_tag(person.avatar)%>
  Remove <%= form.check_box :remove_avatar%>
<%end%>

并且您可以使用this gem进行ActiveStorage验证。

© www.soinside.com 2019 - 2024. All rights reserved.