Skip to content

attachment-picker Stimulus controller does not sync hidden fields after inline upload #1425

Open

Description

@ksnitsky

The problem
When using Spina::Parts::Attachment in the admin page editor, uploading a new file via the inline upload button results in signed_blob_id and filename being saved as empty strings, even though the Spina::Attachment record is created correctly and the file is attached.

This causes Spina::Parts::Attachment#present? to return false (since it checks signed_blob_id.present?), and ContentPresenter#attachment_url to return nil, making the uploaded file inaccessible in frontend views.

Root Cause

There are two issues in the interaction between the attachment-picker Stimulus controller and the inline upload Turbo Stream response:

1. pick() is never called after inline upload

The attachment-picker controller's pick() method is bound to the change event on the <select> element. When the inline upload Turbo Stream response appends a new <option selected> to the <select>, the browser does not fire a change event (programmatic DOM mutations don't trigger input events). Therefore pick() is never invoked, and the hidden fields signed_blob_id and filename remain at their previous values (empty strings for a new part).

2. Attribute format mismatch between dropdown options and inline upload options

Even if pick() were called, there is an attribute format mismatch:

  • Dropdown options (rendered by the Rails select helper in _form.html.erb) use data-* attributes:

    <option value="1" data-signed-blob-id="eyJ..." data-filename="video.mp4">video.mp4</option>
  • Inline upload options (rendered by parts/attachments/_attachment.html.erb) use plain HTML attributes:

    <option value="1" signed-blob-id="eyJ..." filename="video.mp4" selected>video.mp4</option>

The pick() method reads from option.dataset.signedBlobId and option.dataset.filename, which correspond to data-signed-blob-id and data-filename attributes respectively. These are undefined on inline upload options, so even a manual re-selection after upload would write empty strings.

Steps to Reproduce

  1. Create a page with a part that uses Spina::Parts::Attachment
  2. Edit the page in Spina admin
  3. In the Attachment field, click "Upload" and select a file
  4. Save the page
  5. Inspect the page's JSON content — signed_blob_id will be "" and filename will be ""
  6. page.content(:your_attachment_part).present? returns false

Workaround: After the inline upload completes, manually re-select the same file from the dropdown. This triggers the change event, pick() reads the data-* attributes from the dropdown option (which has them correctly), and the hidden fields are populated.

Environment

  • Ruby 3.4.2
  • Spina 2.20.0
  • Rails 8.0.2
  • attr_json 2.5.1
  • Stimulus 3.x (via @hotwired/stimulus)
  • Turbo (via @hotwired/turbo-rails)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions