由于Rails 6.0升级(从5.2.x开始),ActiveStorage出现了一个问题。

我有一个自定义管理界面,其中“页面”具有字段,每个“字段”都有一个STI type以创建复杂的页面布局。使用Active Storage的Image类型(它是Paperclip,但在Rails 5.2发行后迁移了),通过一个简单的上载模式(没有复杂的直接上载JS)来存储图像。

类的结构如下所示(为简便起见,我删除了多余的代码):


class Page < ApplicationRecord
    has_many :fields, dependent: :destroy
    accepts_nested_attributes_for :fields, allow_destroy: true
end

class Field < ApplicationRecord
    belongs_to :page
end

module Fields
    class Image < Content::Field
        has_one_attached :image
        accepts_nested_attributes_for :image_attachment, allow_destroy: true
    end
end


更新页面时,它是通过嵌套表单属性和对@page.update(permitted_params)的简单调用来实现的。

permitted_params(减去不重要的参数)看起来像这样...

{
    "fields_attributes"=> {
        "0"=> {
            "type"=>"Fields::Image",
            "image"=>#<ActionDispatch::Http::UploadedFile:0x00007ff36cdd9908 @tempfile=#<Tempfile:/var/folders/_t/clkdb5ms365617_039m7y7sc0000gn/T/RackMultipart20191021-38488-4kyp8k.jpg>, @original_filename="image.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"content_page[fields_attributes][0][image]\"; filename=\"image.jpg\"\r\nContent-Type: image/jpeg\r\n">,
            "id"=>"8059"
        }
    }
}


为了维持更新集合而不是覆盖集合的ActiveStorage 5.2行为,我在application.rb中包含以下内容:

config.active_storage.replace_on_assign_to_many = false

但是,由于字段关系是has_one_attached,因此不应影响它。

从日志中,不会开始上传,也不会对Active Storage表进行任何更新,但是会将一个更新写入Page表:

Content::Page Update (5.2ms) UPDATE `pages` SET `pages`.`updated_at` = '2019-10-21 13:58:18' WHERE `pages`.`id` = 105 /*application:myapp,controller:pages,action:update*/

就是这样,没有别的。

但是,如果我在更新方法中byebug然后手动执行更新:

$ img = Fields::Image.new(image: permitted_params.dig("fields_attributes", "0", "image"))
#<Content::Fields::Image id: nil, type: "Content::Fields::Image">
$ img.valid?
# true
$ img.save

   (4.6ms)  BEGIN
  Field Load (1.5ms)  SELECT `fields`.* FROM `fields` WHERE `fields`.`page_id` IS NULL AND (`fields`.`position` IS NOT NULL) ORDER BY `fields`.`position` DESC LIMIT 1
  Fields::Image Create (1.7ms)  INSERT INTO `fields` (`type`) VALUES ('Fields::Image')
  ActiveStorage::Blob Load (1.6ms)  SELECT `active_storage_blobs`.* FROM `active_storage_blobs` INNER JOIN `active_storage_attachments` ON `active_storage_blobs`.`id` = `active_storage_attachments`.`blob_id` WHERE `active_storage_attachments`.`record_id` = 8062 AND `active_storage_attachments`.`record_type` = 'Fields::Image' AND `active_storage_attachments`.`name` = 'image' ORDER BY `active_storage_attachments`.`position` ASC LIMIT 1
  ActiveStorage::Attachment Load (1.6ms)  SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 8062 AND `active_storage_attachments`.`record_type` = 'Fields::Image' AND `active_storage_attachments`.`name` = 'image' ORDER BY `active_storage_attachments`.`position` ASC LIMIT 1
  ActiveStorage::Blob Create (2.7ms)  INSERT INTO `active_storage_blobs` (`key`, `filename`) VALUES ('mnf9brbh9e1kyriummf11kpd7t6q', 'image.jpg')
  ActiveStorage::Attachment Load (2.0ms)  SELECT `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_type` = 'Fields::Image' AND `active_storage_attachments`.`name` = 'image' AND `active_storage_attachments`.`record_id` = 8062 AND (`active_storage_attachments`.`position` IS NOT NULL) ORDER BY `active_storage_attachments`.`position` DESC LIMIT 1
  ActiveStorage::Attachment Create (4.1ms)  INSERT INTO `active_storage_attachments` (`name`, `record_type`, `record_id`) VALUES ('image', 'Fields::Image')
  Fields::Image Update (2.3ms)  UPDATE `fields` SET `fields`.`updated_at` = '2019-10-21 14:24:06' WHERE `fields`.`id` = 8062
   (2.0ms)  COMMIT
  FlatDisk Storage (5.3ms) Uploaded file to key: mnf9brbh9e1kyriummf11kpd7t6q (checksum: ms9Zu1oagR5kGjcci1YfhQ==)
[ActiveJob] Enqueued ActiveStorage::AnalyzeJob (Job ID: 034d495a-01c1-4935-a873-b07fcec35f47) to Sidekiq(active_storage_analysis) with arguments: #<GlobalID:0x00007ff36c2e2090 @uri=#<URI::GID gid://dswt/ActiveStorage::Blob/52786>>

# true


因此,这使我认为这可能与嵌套参数有关,但是我看不到这些问题,因此我对可能发生的事情感到困惑。

图片上传功能可以在网站上的其他地方正常运行,只是在这一位置上无法正常工作。

任何帮助将不胜感激。

谢谢保罗。

编辑:

我将其范围缩小到ActiveStorage,除非模型上的字段(updated_at或表中存在的任何列)也更新,否则不更新映像关联。这似乎触发ActiveRecord保留实例,这触发ActiveStorage上载文件。

最佳答案

经过一堆的试验之后,我得出结论,除非以某种方式更改了模型(例如,触摸updated_at时间戳或另一个编辑其他字段),否则不会更新Active Storage关系。我认为这是Rails的错误。

通过在表单中​​添加<%= f.hidden_field :updated_at, value: DateTime.current %>,我可以强制Active Storage保留文件。

希望这对其他人有帮助。

10-01 07:11
查看更多