Uploading files via Ajax forms with remotipart in Rails 5 - Women Who Code.
52085
post-template-default,single,single-post,postid-52085,single-format-standard,qode-core-1.0.1,ajax_fade,page_not_loaded,,capri child-child-ver-1.0.0,capri-ver-1.6, vertical_menu_with_scroll,smooth_scroll,grid_1200,blog_installed,wpb-js-composer js-comp-ver-4.12.1,vc_responsive
 

Uploading files via Ajax forms with remotipart in Rails 5

Uploading files via Ajax forms with remotipart in Rails 5

Recently I had a hard time trying to make an Ajax form with file attachments. I had an Ajax form ready, then added a nested form for uploading files and went to the browser to test my form by hand. But when I attempted to submit the form with file attachment, I’ve got an error in Rails 5.1.1:

ActionController::InvalidAuthenticityToken in AnswersController#Create

This error looks like a bug, but in fact it is a correct Rails behavior for security reasons, which appeared in Rails 4: AuthenticityToken is not transmitted in Ajax forms, if they upload files. Meaning, that without file attachments the form would have worked, but an Ajax form with file attachments is not going to work by default.

There are many advice on the internet on how to go about this error, but most of them wouldn’t work for your particular case or are unsafe (like adding token in the settings). Still there is one easy workaround, which usually works and is safe and correct: the remotipart gem. Remotipart gem allows to avoid the token error and safely uploads files via Ajax forms. All you need to do is 1) install the remotipart gem and 2) add this line to the application.js file:

//= require jquery.remotipart

right after this line (as recommended in the docs):

//= require jquery_ujs

After these operations my application.js file looked like this:

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery3
//= require jquery_ujs
//= require jquery.remotipart
//= require turbolinks
//= require_tree .

//= require jquery
//= require bootstrap-sprockets

But the token error persisted. I googled, but failed to find any clear answer to this.
Well, the solution appeared to be the following: mess up with the line order in application.js a bit more. Below is how I reordered the lines to finally get rid of the token error:

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery3
//= require jquery
//= require bootstrap-sprockets
//= require turbolinks
//= require jquery_ujs
//= require jquery.remotipart
//= require_tree .

PS error’s console log:

Started POST "/questions/67/answers" for 10.0.2.2 at 2017-08-09 16:43:07 +0000
Cannot render console from 10.0.2.2! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by AnswersController#create as HTML
  Parameters: {"utf8"=>"✓", "answer"=>{"body"=>"loo"}, "commit"=>"Post your answer", "question_id"=>"67"}
Can't verify CSRF token authenticity.
Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms)

 
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
  
actionpack (5.1.1) lib/action_controller/metal/request_forgery_protection.rb:195:in `handle_unverified_request'
actionpack (5.1.1) lib/action_controller/metal/request_forgery_protection.rb:227:in `handle_unverified_request'
devise (4.3.0) lib/devise/controllers/helpers.rb:253:in `handle_unverified_request'
actionpack (5.1.1) lib/action_controller/metal/request_forgery_protection.rb:222:in `verify_authenticity_token'
activesupport (5.1.1) lib/active_support/callbacks.rb:413:in `block in make_lambda'
activesupport (5.1.1) lib/active_support/callbacks.rb:197:in `block (2 levels) in halting'
actionpack (5.1.1) lib/abstract_controller/callbacks.rb:12:in `block (2 levels) in '
activesupport (5.1.1) lib/active_support/callbacks.rb:198:in `block in halting'
activesupport (5.1.1) lib/active_support/callbacks.rb:507:in `block in invoke_before'
activesupport (5.1.1) lib/active_support/callbacks.rb:507:in `each'
activesupport (5.1.1) lib/active_support/callbacks.rb:507:in `invoke_before'
activesupport (5.1.1) lib/active_support/callbacks.rb:130:in `run_callbacks'
actionpack (5.1.1) lib/abstract_controller/callbacks.rb:19:in `process_action'
actionpack (5.1.1) lib/action_controller/metal/rescue.rb:20:in `process_action'
actionpack (5.1.1) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
activesupport (5.1.1) lib/active_support/notifications.rb:166:in `block in instrument'
activesupport (5.1.1) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (5.1.1) lib/active_support/notifications.rb:166:in `instrument'
actionpack (5.1.1) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (5.1.1) lib/action_controller/metal/params_wrapper.rb:252:in `process_action'
activerecord (5.1.1) lib/active_record/railties/controller_runtime.rb:22:in `process_action'
actionpack (5.1.1) lib/abstract_controller/base.rb:124:in `process'
actionview (5.1.1) lib/action_view/rendering.rb:30:in `process'
actionpack (5.1.1) lib/action_controller/metal.rb:189:in `dispatch'
actionpack (5.1.1) lib/action_controller/metal.rb:253:in `dispatch'
actionpack (5.1.1) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack (5.1.1) lib/action_dispatch/routing/route_set.rb:31:in `serve'
actionpack (5.1.1) lib/action_dispatch/journey/router.rb:46:in `block in serve'
actionpack (5.1.1) lib/action_dispatch/journey/router.rb:33:in `each'
actionpack (5.1.1) lib/action_dispatch/journey/router.rb:33:in `serve'
actionpack (5.1.1) lib/action_dispatch/routing/route_set.rb:832:in `call'
remotipart (1.3.1) lib/remotipart/middleware.rb:32:in `call'
warden (1.2.7) lib/warden/manager.rb:36:in `block in call'
warden (1.2.7) lib/warden/manager.rb:35:in `catch'
warden (1.2.7) lib/warden/manager.rb:35:in `call'
rack (2.0.3) lib/rack/etag.rb:25:in `call'
rack (2.0.3) lib/rack/conditional_get.rb:38:in `call'
rack (2.0.3) lib/rack/head.rb:12:in `call'
rack (2.0.3) lib/rack/session/abstract/id.rb:232:in `context'
rack (2.0.3) lib/rack/session/abstract/id.rb:226:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/cookies.rb:613:in `call'
activerecord (5.1.1) lib/active_record/migration.rb:556:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/callbacks.rb:26:in `block in call'
activesupport (5.1.1) lib/active_support/callbacks.rb:97:in `run_callbacks'
actionpack (5.1.1) lib/action_dispatch/middleware/callbacks.rb:24:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/debug_exceptions.rb:59:in `call'
web-console (3.5.1) lib/web_console/middleware.rb:135:in `call_app'
web-console (3.5.1) lib/web_console/middleware.rb:20:in `block in call'
web-console (3.5.1) lib/web_console/middleware.rb:18:in `catch'
web-console (3.5.1) lib/web_console/middleware.rb:18:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
railties (5.1.1) lib/rails/rack/logger.rb:36:in `call_app'
railties (5.1.1) lib/rails/rack/logger.rb:24:in `block in call'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:69:in `block in tagged'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:69:in `tagged'
railties (5.1.1) lib/rails/rack/logger.rb:24:in `call'
sprockets-rails (3.2.0) lib/sprockets/rails/quiet_assets.rb:13:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/request_id.rb:25:in `call'
rack (2.0.3) lib/rack/method_override.rb:22:in `call'
rack (2.0.3) lib/rack/runtime.rb:22:in `call'
activesupport (5.1.1) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/static.rb:125:in `call'
rack (2.0.3) lib/rack/sendfile.rb:111:in `call'
railties (5.1.1) lib/rails/engine.rb:522:in `call'
puma (3.8.2) lib/puma/configuration.rb:224:in `call'
puma (3.8.2) lib/puma/server.rb:600:in `handle_request'
puma (3.8.2) lib/puma/server.rb:435:in `process_client'
puma (3.8.2) lib/puma/server.rb:299:in `block in run'
puma (3.8.2) lib/puma/thread_pool.rb:120:in `block in spawn_thread'
No Comments

Post a Comment