hyrax: Adding existing works to existing collection fails

Descriptive summary

Given I have a work owned by me And I have a collection owned by me When I visit my dashboard And select my work And click “Add to Collection” And select my collection And click “Update Collection” Then I should not see ActionController::InvalidAuthenticityToken

Expected behavior

My work should be added to my collection

Actual behavior

Started PUT "/collections/g158bh28p?locale=en" for 127.0.0.1 at 2017-06-12 10:21:54 -0400
Processing by Hyrax::CollectionsController#update as HTML
  Parameters: {"authenticity_token"=>"MdqIljoqgvEyFCRiXnKmGPbxMu8y7ykUlMWUamXLLqMkoLky/vAbpSiLprweauguBwQVCIeAYKTCEYrFzmPVLg==", "batch_document_ids"=>["5m60qr88b"], "collection"=>{"members"=>"add"}, "locale"=>"en", "id"=>"g158bh28p"}
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 <module:Callbacks>'
  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 `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 `serve'
  actionpack (5.1.1) lib/action_dispatch/routing/route_set.rb:832:in `call'
  railties (5.1.1) lib/rails/engine.rb:522:in `call'
  railties (5.1.1) lib/rails/railtie.rb:185:in `method_missing'
  actionpack (5.1.1) lib/action_dispatch/routing/mapper.rb:17:in `block in <class:Constraints>'
  actionpack (5.1.1) lib/action_dispatch/routing/mapper.rb:46: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 `serve'
  actionpack (5.1.1) lib/action_dispatch/routing/route_set.rb:832: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 `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'
  active-fedora (11.2.0) lib/active_fedora/ldp_cache.rb:26:in `call'
  flipflop (2.3.1) lib/flipflop/feature_cache.rb:12: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'
  better_errors (2.1.1) lib/better_errors/middleware.rb:84:in `protected_app_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:79:in `better_errors_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:57:in `call'
  actionpack (5.1.1) lib/action_dispatch/middleware/debug_exceptions.rb:59: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.9.1) lib/puma/configuration.rb:224:in `call'
  puma (3.9.1) lib/puma/server.rb:602:in `handle_request'
  puma (3.9.1) lib/puma/server.rb:435:in `process_client'
  puma (3.9.1) lib/puma/server.rb:299:in `block in run'
  puma (3.9.1) lib/puma/thread_pool.rb:120:in `block in spawn_thread'

Steps to reproduce the behavior

  1. Create a work and collection
  2. From the user dashboard, select the work and add it to the collection

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 36 (35 by maintainers)

Commits related to this issue

Most upvoted comments

I may have figured out what’s happening in the case of batch adding works to a collection. It relates to turbolinks and jquery-ujs.

It appears the default setting is to generate a CSRF token for each form, i.e. Rails.application.config.action_controller.per_form_csrf_tokens = true. This contradicts what we see when a page loads without turbolinks, the tokens in the forms and the global token in the meta tag match. As it turns out jquery-ujs executes $.rails.refreshCSRFTokens() on page loads which copies the token from the meta tag to the form inputs. When a page loads with turbolinks the JS that copies the token is not executed. So this how we end up with different tokens in the HTML.

Normally, this would not be a problem because all of the CSRF tokens that were loaded are valid. Here’s the interesting part, in this particular case the token was generated for the action /dashboard/collections/collection_replace_id, but the actual action depends on the selected collection. Selecting a collection modifies the action path, thus invalidating the token. Using the global token (the one defined in the meta tag) works because it is not specific to the action.

With that being said, it seems like setting Rails.application.config.action_controller.per_form_csrf_tokens = false would solve the problem.

The method I was using to remove turbolinks was incomplete (removing it from application.js and then recompiling assets). When I remove it from the application’s Gemfile and bundle (also removing it from application.js), this error no longer happens.

Worth saying, again, that this is not an issue we’ve seen in Hyku despite it using the same version of Rails (5.1.2) and Turbolinks (5.0.1) that I’ve been testing with a vanilla Hyrax test app today.