Search code examples
ruby-on-railsrails-activestorage

Active Storage on a remote true form. Invalid Authenticity error and wrong controller format


After upgrading my app to Rails 5.2, I've found some time to look at Active Storage. Following the guide, I've installed it and ran the migrations necessary.

On my User model I want to attach an avatar as per the example here: Edge Guide for Active Storage

The error I am receiving upon submitting my form is ActionController::InvalidAuthenticityToken

<%= form_for @user, remote: true do |f| %>
  <%# Other user fields redacted %>

  <div class="form-group">
    <%= f.label :avatar %>
    <%= f.file_field :avatar %>
  </div>

  <%= f.submit "Save", remote: true %>

<% end %>

I changed the form_for to include authenticity_token: true like this:

<%= form_for @user, remote: true, authenticity_token: true do |f| %>

This removed my authenticity error and inserted the file into my DB, however this has caused an Unknown format error, in that it is routing to my controller with html instead of js.

Logs:

Started PATCH "/users/22" for 127.0.0.1 at 2018-11-07 13:36:22 +0000
Processing by UsersController#update as HTML

Disk Storage (5.7ms) Uploaded file to key: aJQ3m2skk8zkHguqvhjV6tNk (checksum: 7w6T1YJX2LNIU9oPxG038w==)
ActiveStorage::Blob Create (23.6ms)  INSERT INTO `active_storage_blobs` (`key`, `filename`, `content_type`, `metadata`, `byte_size`, `checksum`, `created_at`) VALUES ('aJQ3m2skk8zkHguqvhjV6tNk', 'Dq3gtJjU0AAbdIj.jpg-large.jpeg', 'image/jpeg', '{\"identified\":true}', 50642, '7w6T1YJX2LNIU9oPxG038w==', '2018-11-07 13:36:22')
ActiveStorage::Attachment Create (3.4ms)  INSERT INTO `active_storage_attachments` (`name`, `record_type`, `record_id`, `blob_id`, `created_at`) VALUES ('avatar', 'User', 22, 1, '2018-11-07 13:36:22')
 (9.4ms)  ROLLBACK
Completed 406 Not Acceptable in 630ms (ActiveRecord: 93.1ms)

ActionController::UnknownFormat (ActionController::UnknownFormat):

Users#Update

def update
  respond_to do |format|

    if @user.update(user_params)
      flash.now[:notice] = 'User saved successfully!'
      format.js do
        @users = User.all
      end
    else
      flash.now[:alert] = @user.errors.full_messages.to_sentence
      format.js do
        @users = User.all
        render layout: false, content_type: 'text/javascript'
      end
    end

  end
end

Any ideas as to why it is being submitted as HTML instead of JS?

Edit: Form Markup

<form class="edit_user" id="edit_user_22" enctype="multipart/form-data" action="/users/22" accept-charset="UTF-8" data-remote="true" method="post">

Solution

  • After much trial & error, it took using the Direct Upload feature of Active Storage to allow this to work. Allow me to explain my findings:

    remote: true, multipart: true don't play well together. See this stack overflow post for more details. Essentially you need to use jQuery or a gem to submit files remotely.

    Following this edgeguides post (direct uploads). It seems as though when you click on submit; direct upload will catch the submit event and submit the file directly to a cloud server (or local in my dev case). It will then use the reference of that image in the form submit, instead of submitting the actual image.

    This hit my Users#update using JS and successfully attached the Avatar.