Description
Calling Spree::Api checkouts#update
from the sandbox in production mode causes an exception in Metal decorator. This runs fine in dev
mode.
INFO -- : [7601de39-c1f2-4ed3-ba4e-6956b99e4c95] Completed 401 Unauthorized in 218ms (ActiveRecord: 0.5ms)
FATAL -- : [7601de39-c1f2-4ed3-ba4e-6956b99e4c95]
FATAL -- : [7601de39-c1f2-4ed3-ba4e-6956b99e4c95] NameError (undefined local variable or method `env' for #<Spree::Api::V1::CheckoutsController:0x0055f
315ceea10>):
FATAL -- : [7601de39-c1f2-4ed3-ba4e-6956b99e4c95]
FATAL -- : [7601de39-c1f2-4ed3-ba4e-6956b99e4c95] .../bundler/gems/spree_auth_devise-541db70aeccf/app/controllers/metal_dec
orator.rb:4:in `spree_current_user'
Context
# For the API
ActionController::Metal.class_eval do
def spree_current_user
@spree_current_user ||= env['warden'].user
end
end
Reproduction
-
Get the latest spree source from github master. (92c6808aabec0af6fb57d91965b899c7c4fcfda1)
-
Clone `[email protected]:saravanak/spree_8569.git
-
Follow the readme from the above repo to run the specs.
-
Generate the sandbox application and start the server in dev mode.
-
The specs runs fine with the following(Bear with this failure for the moment!)
....
expected: "payment"
got: "complete"
(compared using ==)
# ./spec/replicate_issue_spec.rb:128:in `block (4 levels) in <top (required)>'
Finished in 24.13 seconds (files took 0.88129 seconds to load)
3 examples, 1 failure, 1 pending
-
Copy the
db/development.sqlite3
asdb/production.sqlite3
and include thesecret_key_base
value insandbox/environment.yml
. This prepares for the prod run. -
Run in prod mode:
RAILS_ENV=production rails s -e production
-
2 specs now fail:
Failures:
1) Order update with an empty order and then taking it through to the PAYMENT state remains in the payment state when updating payment using the checkout API when requesting to stagnate
Failure/Error: expect(response.code).to eq(200)
expected: 200
got: 500
(compared using ==)
# ./spec/replicate_issue_spec.rb:126:in `block (4 levels) in <top (required)>'
2) Order update with an empty order and then taking it through to the PAYMENT state remains transitions to the complete state when updating payment using the checkout API
Failure/Error: expect(response.code).to eq(200)
expected: 200
got: 500
(compared using ==)
# ./spec/replicate_issue_spec.rb:142:in `block (4 levels) in <top (required)>'
Finished in 13.72 seconds (files took 0.11461 seconds to load)
3 examples, 2 failures, 1 pending
Analysis
The issue occurs due to the following reasons:
-
The
production
mode uses the configconfig.eager_load = true
, which loads theActionController::Metal
class_eval in theapp/controllers/metal_decorator.rb
file. -
The
CheckoutsController
uses thebefore_action
forupdate
:
before_action :associate_user, only: :update
-
This causes the
try_spree_current_user
>spree_current_user
>@spree_current_user ||= env['warden'].user
sequence to be called. -
According to this, rails wraps
env
within therequest
object.
Possible Fix
Change env
to request.env
:
ActionController::Metal.class_eval do
def spree_current_user
@spree_current_user ||= request.env['warden'].user
end
end