在 Rails 6 活动存储中更新记录时不要清除图像

Do Not purge image when updating record in Rails 6 Active Storage

我已经研究这个问题几天了,似乎找不到解决方案。

我有一个 Rails 6 的模型,用于 has_one_attached :image

的柱

用户可以创建新栏并附加图像。这很好用。

当用户编辑酒吧名称等酒吧信息并提交该信息时,默认情况下 Active Storage 会清除最初上传的图片,即使没有提交新图片也是如此。

在编辑过程中,如果用户没有提交新图片,而只是更改了记录,例如酒吧名称,我如何防止 Active Storage 自动清除图片?我想保留与 Bar 记录关联的图像。

我已经在我的模型中尝试 dependent: :purge_later 但没有成功。我也尝试过提交没有图像参数的参数 if bar_info.image.attached?

我的模型bar_info.rb

class BarInfo < ApplicationRecord
    belongs_to :user
    has_many :bar_specials, dependent: :destroy
    has_one_attached :image
    validates :user_id, presence: true
    validates :barname, presence: true, length: { maximum: 100 }
    validates :city, presence: true, length: { maximum: 50 }
    validates :state, presence: true, length: { maximum: 50 }
    validates :image, content_type: { in: %w[image/jpeg image/gif image/png],
                                            message: "must be a valid image format" },
                          size:         { less_than: 5.megabytes,
                                          message: "should be less than 5MB" }
end

我的控制器bar_infos_controller.rb

class BarInfosController < ApplicationController
def update
        @bar_info = BarInfo.find(params[:id])
        @bar_info.user_id = current_user.id
        @bar_info.image.attach(params[:bar_info][:image])
        if @bar_info.update(bar_info_params)
            flash[:notice] = "Bar Info Updated!"
            redirect_to bar_info_path(@bar_info)
        else
            render "edit"
        end
end

private

        def bar_info_params
            attributes = [ :barname, :city, :state, :image ]
            params.require(:bar_info).permit(attributes)
        end
end

我的编辑视图_form.html.erb

<div class="row">
    <div class="col-md 6">
        <%= form_with(model: @bar_info, local: true) do |f| %>
        <%= render 'shared/error_messages', object: f.object %>

        <%= f.label "Bar Name (required)" %>
        <%= f.text_area :barname, placeholder: "Bar name here", class: "form-control", size: "70x1" %>

        <%= f.label "City (required)" %>
        <%= f.text_area :city, placeholder: "San Diego", class: "form-control", size: "70x1" %>

        <%= f.label "State (required)" %>
        <%= f.select :state, CS.states(:us), class: "form-control" %>

        <span class="image">
            <p>Upload an image of Bar here!</p>
            <%= f.file_field :image, accept: "image/jpeg,image/gif,image/png" %>
        </span>

        <%= f.submit "Submit", class: "btn btn-primary" %>
        <% end %>

        <script type="text/javascript">
            $("#bar_info_image").bind("change", function() {
                const size_in_megabytes = this.files[0].size/1024/1024;
                if (size_in_megabytes > 5) {
                    alert("Maximum file size is 5MB. Please choose a smaller file.");
                    $("$bar_info_image").val("");
                }
            });
        </script>
    </div>
</div>

bar_infos 路线:

bar_infos     GET    /bar_infos(.:format)          bar_infos#index
              POST   /bar_infos(.:format)          bar_infos#create
new_bar_info  GET    /bar_infos/new(.:format)      bar_infos#new
edit_bar_info GET    /bar_infos/:id/edit(.:format) bar_infos#edit
bar_info      GET    /bar_infos/:id(.:format)      bar_infos#show
              PATCH  /bar_infos/:id(.:format)      bar_infos#update
              PUT    /bar_infos/:id(.:format)      bar_infos#update
              DELETE /bar_infos/:id(.:format)      bar_infos#destroy

TL;DR 我想编辑酒吧的名称并仍然保留随它上传的原始图片。 Active Storage 当前会在更新时清除该映像。

谢谢。

这是因为您的 update 控制器操作中的这一行:

      def update 
        ...
        @bar_info.image.attach(params[:bar_info][:image])
        ...
      end

如果用户没有在编辑操作中填写图像,您会将图像设置为 nil,这会从 activestorage 中删除文件。您应该将此更新完全保留在 ActiveRecords update 操作上。您在允许的参数中有图像,因此它应该可以正常工作:

      def update
        @bar_info = BarInfo.find(params[:id])
        @bar_info.user_id = current_user.id

        if @bar_info.update(bar_info_params)
          flash[:notice] = "Bar Info Updated!"
          redirect_to bar_info_path(@bar_info)
        else
          render "edit"
        end
      end

private

      def bar_info_params
        attributes = [ :barname, :city, :state, :image ]
        params.require(:bar_info).permit(*attributes)
      end

(而且我认为 permit 调用 params.require(:bar_info).permit(*attributes) 中应该有 *