ActiveStorage не сохраняет большой двоичный объект во вложении после обновления Rails 6.0 - PullRequest
2 голосов
/ 21 октября 2019

У меня проблема с ActiveStorage, которая возникла из-за обновления Rails 6.0 (с версии 5.2.x).

У меня есть пользовательский интерфейс администратора, где у страниц есть поля, а у каждого поля есть STI type для создания сложных макетов страниц. Тип Image, который использует Active Storage (это был 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 для загрузки файла.

1 Ответ

2 голосов
/ 25 октября 2019

После нескольких тренировок я понял, что отношения Active Storage не обновляются, если только модель не была изменена каким-либо образом, например, прикосновением к отметке времени updated_at или другим редактированием другого поля - я думаю, что этоошибка Rails.

Добавив <%= f.hidden_field :updated_at, value: DateTime.current %> в мои формы, я смог заставить Active Storage сохранить файл.

Надеюсь, это поможет кому-то еще.

...