Skip to content

Spree::Api 'checkouts#update' in production mode causes exception in Metal decorator #411

Open
@saravanak

Description

@saravanak

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

Code in question:

# For the API
ActionController::Metal.class_eval do
  def spree_current_user
    @spree_current_user ||= env['warden'].user
  end
end

Reproduction

  1. Get the latest spree source from github master. (92c6808aabec0af6fb57d91965b899c7c4fcfda1)

  2. Clone `[email protected]:saravanak/spree_8569.git

  3. Follow the readme from the above repo to run the specs.

  4. Generate the sandbox application and start the server in dev mode.

  5. 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

  1. Copy the db/development.sqlite3 as db/production.sqlite3 and include the secret_key_base value in sandbox/environment.yml. This prepares for the prod run.

  2. Run in prod mode: RAILS_ENV=production rails s -e production

  3. 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:

  1. The production mode uses the config config.eager_load = true, which loads the ActionController::Metal class_eval in the app/controllers/metal_decorator.rb file.

  2. The CheckoutsController uses the before_action for update:

before_action :associate_user, only: :update
  1. This causes the try_spree_current_user > spree_current_user > @spree_current_user ||= env['warden'].user sequence to be called.

  2. According to this, rails wraps env within the request 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions