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
- Create a work and collection
- 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
- Restores ability to add existing works to existing collections via dashboard Refs #1191 This is a workaround that restores this functionality. We suspect the bug itself is a regression in Rails or T... — committed to samvera/hyrax by mjgiarlo 7 years ago
- Disable turbolinks on links to my_works_path Refs #1191 Follows #1605 — committed to samvera/hyrax by mjgiarlo 7 years ago
- Avoid ‘Can't verify CSRF token authenticity.’ when saving a collection Related to issues * #1191 - Adding existing works to existing collection fails * #1489 - Throwing ActionController::InvalidAuthe... — committed to samvera/hyrax by elrayle 6 years ago
- Fix for #2873 - CSRF Exception after adding to Collections/Sharing - Found the root issue is related to turbolinks + jquery-ujs + a button that uses ajax to post. This may also fix #1191. Adding a ca... — committed to samvera/hyrax by jgondron 6 years ago
I may have figured out what’s happening in the case of batch adding works to a collection. It relates to
turbolinks
andjquery-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.