这是已经存在了一段时间的问题,直到今天,我仍然没有找到解决方案。我已经看到了一些类似的问题,但并不太了解我遇到的问题。
自从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 %>
预期的行为是
发生的情况是,您选择了错误的文件类型,它的确阻止了记录的保存,这很好,但是它仍然“看到”了非持久记录上的附件。因此,尽管在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
为了防止错误,您可以使用persisted?
<% if person.avatar.attached? && person.avatar.persisted? %>
<%= image_tag(person.avatar)%>
Remove <%= form.check_box :remove_avatar%>
<%end%>
并且您可以使用this gem进行ActiveStorage验证。