我最近将我的项目升级到最新的 Rails 版本(5.2)以获得ActiveStorage
- 一个处理附件上传到云服务(如 AWS S3、Google 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.
那是什么意思?如何更改用户的头像?
错误原因
这个错误是由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 关系一致地工作是有意义的,并且最好让开发人员在附加新记录之前明确清除原始记录,而不是自动执行此操作(这可能有点自以为是) )。
资源:
- 源代码为has_one错误引发行为 https://github.com/rails/rails/blob/master/activerecord/lib/active_record/associations/has_one_association.rb#L92
- 测试用例has_one错误引发行为 https://github.com/rails/rails/blob/master/activerecord/test/cases/associations/has_one_associations_test.rb#L479
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)