首页 文章

如何在ActiveStorage中更新附件(Rails 5.2)

提问于
浏览
5

我最近将我的项目升级到最新的Rails版本(5.2)以获得 ActiveStorage - 一个处理附件上传到AWS S3,Google Cloud等 Cloud 服务的库 .

几乎一切都很好 . 我可以上传和附加图像

user.avatar.attach(params[:file])

接收它

user.avatar.service_url

但现在我想替换/更新用户的头像 . 我以为我可以跑

user.avatar.attach(params[:file])

再次 . 但这会引发错误:

ActiveRecord::RecordNotSaved: Failed to remove the existing associated avatar_attachment. The record failed to save after its foreign key was set to nil.

那是什么意思?如何更改用户头像?

3 回答

  • 5

    使用 has_one_attached 时,可以在 attach 之前调用 purge_later

    user.avatar.purge_later
    user.avatar.attach(params[:file])
    

    Update

    Rails now purges previous attachment automatically (since Aug 29th) .

  • 2

    我有同样的问题与图像保存 . 我希望这个能帮上忙

    class User < ApplicationRecord
      has_one_attached :avatar
    end
    

    让我们看看表单和控制器

    = simple_form_for(@user) do |f|
      = f.error_notification
      .form-inputs
        = f.input :name
        = f.input :email
        = f.input :avatar, as: :file
    
      .form-actions
        = f.button :submit
    

    控制器/ posts_controller.rb

    def create
        @user = User.new(post_params)
        @user.avatar.attach(params[:post][:avatar])
        respond_to do |format|
          if @user.save
            format.html { redirect_to @user, notice: 'Post was successfully created.' }
            format.json { render :show, status: :created, location: @user }
          else
            format.html { render :new }
            format.json { render json: @user.errors, status: :unprocessable_entity }
          end
        end
      end
    
  • 1

    错误原因

    模型和附件记录之间的 has_one 关联引发此错误 . 之所以会发生这种情况,是因为尝试用新的附件替换原始附件将孤立原始附件并导致它使 belongs_to 关联的外键约束失败 . 这是所有ActiveRecord has_one 关系的行为(即它不是特定于ActiveStorage) .

    一个类似的例子

    class User < ActiveRecord::Base
       has_one :profile
    end
    class Profile < ActiveRecord::Base
       belongs_to :user
    end
    
    # create a new user record
    user = User.create!
    
    # create a new associated profile record (has_one)
    original_profile = user.create_profile!
    
    # attempt to replace the original profile with a new one
    user.create_profile! 
     => ActiveRecord::RecordNotSaved: Failed to remove the existing associated profile. The record failed to save after its foreign key was set to nil.
    

    在尝试创建新配置文件时,ActiveRecord尝试将原始配置文件的 user_id 设置为 nil ,这会使 belongs_to 记录的外键约束失败 . 我相信这基本上是当您尝试使用ActiveStorage将新文件附加到模型时发生的事情......这样做会尝试使原始附件记录的外键无效,这将失败 .

    解决方案

    has_one 关系的解决方案是在尝试创建新记录之前销毁相关记录(即在尝试附加另一个记录之前清除附件) .

    user.avatar.purge # or user.avatar.purge_later
    user.avatar.attach(params[:file])
    

    这是理想的行为吗?

    在尝试为has_one关系添加新记录时,ActiveStorage是否应该自动清除原始记录是对核心团队提出的另一个问题......

    IMO让它与所有其他has_one关系一致地工作是有道理的,并且可能最好让开发人员明确关于在附加新记录之前清除原始记录而不是自动执行(这可能有点冒昧) ) .

    Resources:

相关问题