Agile Web Development with Rails, Edition 4
    
      10.2 Iteration E2: Handling Errors
      9.4 Playtime
    
    
      10.1 Iteration E1: Creating a Smarter Cart
    
    Change the cart to track the quantity of each product.
    Add a quantity column to the line_item table in the database.
    rails generate migration add_quantity_to_line_items quantity:integer
          invoke  active_record
          create    db/migrate/20170602134112_add_quantity_to_line_items.rb
    Modify the migration to add a default value for the new column
    edit db/migrate/20170602134112_add_quantity_to_line_items.rb
    class AddQuantityToLineItems < ActiveRecord::Migration
      def change
        add_column :line_items, :quantity, :integer, default: 1
      end
    end
    Apply the migration
    rake db:migrate
    mv 20170602134112_add_quantity_to_line_items.rb 20170602000004_add_quantity_to_line_items.rb
    == 20170602000004 AddQuantityToLineItems: migrating ===========================
    -- add_column(:line_items, :quantity, :integer, {:default=>1})
       -> 0.0005s
    == 20170602000004 AddQuantityToLineItems: migrated (0.0005s) ==================
     
    Create a method to add a product to the cart by either incrementing the quantity of an existing line item, or creating a new line item.
    edit app/models/cart.rb
     
      def add_product(product)
        current_item = line_items.find_by(product_id: product.id)
        if current_item
          current_item.quantity += 1
        else
          current_item = line_items.build(product_id: product.id)
        end
        current_item
      end
    Replace the call to LineItem.new with a call to the new method.
    edit app/controllers/line_items_controller.rb
      def create
        product = Product.find(params[:product_id])
        @line_item = @cart.add_product(product)
     
        respond_to do |format|
          if @line_item.save
            format.html { redirect_to @line_item.cart,
              notice: 'Line item was successfully created.' }
            format.json { render :show,
              status: :created, location: @line_item }
          else
            format.html { render :new }
            format.json { render json: @line_item.errors,
              status: :unprocessable_entity }
          end
        end
      end
    Update the view to show both columns.
    edit app/views/carts/show.html.erb
    <p id="notice"><%= notice %></p>
     
    <h2>Your Pragmatic Cart</h2>
    <ul>    
      <% @cart.line_items.each do |item| %>
        <li><%= item.quantity %> × <%= item.product.title %></li>
      <% end %>
    </ul>
    Look at the cart, and see that's not exactly what we intended
    get /carts/1
    
  
    
    
      
      
  
        
Your Pragmatic Cart
    
    - 1 × Seven Mobile Apps in Seven Weeks
- 1 × Seven Mobile Apps in Seven Weeks
 
     
  
       
    
    Generate a migration to combine/separate items in carts.
    rails generate migration combine_items_in_cart
          invoke  active_record
          create    db/migrate/20170602134114_combine_items_in_cart.rb
    Fill in the self.up method
    edit db/migrate/20170602134114_combine_items_in_cart.rb
      def up
        # replace multiple items for a single product in a cart with a
        # single item
        Cart.all.each do |cart|
          # count the number of each product in the cart
          sums = cart.line_items.group(:product_id).sum(:quantity)
     
          sums.each do |product_id, quantity|
            if quantity > 1
              # remove individual items
              cart.line_items.where(product_id: product_id).delete_all
     
              # replace with a single item
              item = cart.line_items.build(product_id: product_id)
              item.quantity = quantity
              item.save!
            end
          end
        end
      end
    Combine entries
    rake db:migrate
    mv 20170602134114_combine_items_in_cart.rb 20170602000005_combine_items_in_cart.rb
    == 20170602000005 CombineItemsInCart: migrating ===============================
    == 20170602000005 CombineItemsInCart: migrated (0.0234s) ======================
     
    Verify that the entries have been combined.
    get /carts/1
    
  
    
    
      
      
  
        
Your Pragmatic Cart
    
    - 2 × Seven Mobile Apps in Seven Weeks
 
     
  
       
    
    Fill in the self.down method
    edit db/migrate/20170602000005_combine_items_in_cart.rb
      def down
        # split items with quantity>1 into multiple items
        LineItem.where("quantity>1").each do |line_item|
          # add individual items
          line_item.quantity.times do 
            LineItem.create(
              cart_id: line_item.cart_id,
              product_id: line_item.product_id,
              quantity: 1
            )
          end
     
          # remove original item
          line_item.destroy
        end
      end
    Separate out individual items.
    rake db:rollback
    == 20170602000005 CombineItemsInCart: reverting ===============================
    == 20170602000005 CombineItemsInCart: reverted (0.0089s) ======================
     
    rake db:migrate:status
     
    database: /home/rubys/git/awdwr/edition4/work-226-42/depot/db/development.sqlite3
     
     Status   Migration ID    Migration Name
    --------------------------------------------------
       up     20170602000001  Create products
       up     20170602000002  Create carts
       up     20170602000003  Create line items
       up     20170602000004  Add quantity to line items
      down    20170602000005  Combine items in cart
     
    mv db/migrate/20170602000005_combine_items_in_cart.rb db/migrate/20170602000005_combine_items_in_cart.bak
    Every item should (once again) only have a quantity of one.
    get /carts/1
    
  
    
    
      
      
  
        
Your Pragmatic Cart
    
    - 1 × Seven Mobile Apps in Seven Weeks
- 1 × Seven Mobile Apps in Seven Weeks
 
     
  
       
    
    Recombine the item data.
    mv db/migrate/20170602000005_combine_items_in_cart.bak db/migrate/20170602000005_combine_items_in_cart.rb
    rake db:migrate
    == 20170602000005 CombineItemsInCart: migrating ===============================
    == 20170602000005 CombineItemsInCart: migrated (0.0232s) ======================
     
    Add a few products to the order.
    post /line_items?product_id=2
    
    
You are being 
redirected.    
get http://localhost:3000/carts/1
    
  
    
    
      
      
  
        Line item was successfully created.
Your Pragmatic Cart
    
    - 2 × Seven Mobile Apps in Seven Weeks
- 1 × Rails, Angular, Postgres, and Bootstrap
 
     
  
       
    
    post /line_items?product_id=3
    
    
You are being 
redirected.    
get http://localhost:3000/carts/1
    
  
    
    
      
      
  
        Line item was successfully created.
Your Pragmatic Cart
    
    - 3 × Seven Mobile Apps in Seven Weeks
- 1 × Rails, Angular, Postgres, and Bootstrap
 
     
  
       
    
    Try something malicious.
    get /carts/wibble
    HTTP Response Code: 404
    
  
    ActiveRecord::RecordNotFound
      in CartsController#show
  
  Couldn't find Cart with 'id'=wibble
      
      
        Extracted source (around line #155):
      
      
        
          
            | 
153
154
155
156
157
158
               | 
        record = s.execute([id], self, connection).first
         unless record
           raise RecordNotFound, "Couldn't find #{name} with '#{primary_key}'=#{id}"
         end
         record
       rescue RangeError
 | 
        
       
     
    
      
        Extracted source (around line #67):
      
      
        
          
            | 
65
66
67
68
69
70
               | 
    # Use callbacks to share common setup or constraints between actions.
     def set_cart
       @cart = Cart.find(params[:id])
     end
 
     # Never trust parameters from the scary internet, only allow the white list through.
 | 
        
       
     
    
      
        Extracted source (around line #432):
      
      
        
          
            | 
430
431
432
433
434
435
               | 
        case filter
         when Symbol
           lambda { |target, _, &blk| target.send filter, &blk }
         when String
           l = eval "lambda { |value| #{filter} }"
           lambda { |target, value| target.instance_exec(value, &l) }
 | 
        
       
     
    
      
        Extracted source (around line #145):
      
      
        
          
            | 
143
144
145
146
147
148
               | 
             if !halted && user_conditions.all? { |c| c.call(target, value) }
               result = user_callback.call target, value
               env.halted = halted_lambda.call(target, result)
               if env.halted
                 target.send :halted_callback_hook, filter
 | 
        
       
     
    
      
        Extracted source (around line #145):
      
      
        
          
            | 
143
144
145
146
147
148
               | 
             if !halted && user_conditions.all? { |c| c.call(target, value) }
               result = user_callback.call target, value
               env.halted = halted_lambda.call(target, result)
               if env.halted
                 target.send :halted_callback_hook, filter
 | 
        
       
     
    
      
        Extracted source (around line #504):
      
      
        
          
            | 
502
503
504
505
506
507
               | 
       def call(*args)
         @before.each { |b| b.call(*args) }
         value = @call.call(*args)
         @after.each { |a| a.call(*args) }
         value
 | 
        
       
     
    
      
        Extracted source (around line #504):
      
      
        
          
            | 
502
503
504
505
506
507
               | 
       def call(*args)
         @before.each { |b| b.call(*args) }
         value = @call.call(*args)
         @after.each { |a| a.call(*args) }
         value
 | 
        
       
     
    
      
        Extracted source (around line #504):
      
      
        
          
            | 
502
503
504
505
506
507
               | 
       def call(*args)
         @before.each { |b| b.call(*args) }
         value = @call.call(*args)
         @after.each { |a| a.call(*args) }
         value
 | 
        
       
     
    
      
        Extracted source (around line #504):
      
      
        
          
            | 
502
503
504
505
506
507
               | 
       def call(*args)
         @before.each { |b| b.call(*args) }
         value = @call.call(*args)
         @after.each { |a| a.call(*args) }
         value
 | 
        
       
     
    
      
        Extracted source (around line #92):
      
      
        
          
            | 
90
91
92
93
94
95
               | 
        runner = callbacks.compile
         e = Filters::Environment.new(self, false, nil, block)
         runner.call(e).value
       end
     end
 
 | 
        
       
     
    
      
        Extracted source (around line #778):
      
      
        
          
            | 
776
777
778
779
780
781
               | 
          module_eval <<-RUBY, __FILE__, __LINE__ + 1
             def _run_#{name}_callbacks(&block)
               __run_callbacks__(_#{name}_callbacks, &block)
             end
           RUBY
         end
 | 
        
       
     
    
      
        Extracted source (around line #81):
      
      
        
          
            | 
79
80
81
82
83
84
               | 
    #   end
     def run_callbacks(kind, &block)
       send "_run_#{kind}_callbacks", &block
     end
 
     private
 | 
        
       
     
    
      
        Extracted source (around line #19):
      
      
        
          
            | 
17
18
19
20
21
22
               | 
    # process_action callbacks around the normal behavior.
     def process_action(*args)
       run_callbacks(:process_action) do
         super
       end
     end
 | 
        
       
     
    
      
        Extracted source (around line #29):
      
      
        
          
            | 
27
28
29
30
31
32
               | 
    private
       def process_action(*args)
         super
       rescue Exception => exception
         request.env['action_dispatch.show_detailed_exceptions'] ||= show_detailed_exceptions?
         rescue_with_handler(exception) || raise(exception)
 | 
        
       
     
    
      
        Extracted source (around line #32):
      
      
        
          
            | 
30
31
32
33
34
35
               | 
      ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload|
         begin
           result = super
           payload[:status] = response.status
           result
         ensure
 | 
        
       
     
    
      
        Extracted source (around line #164):
      
      
        
          
            | 
162
163
164
165
166
167
               | 
      def instrument(name, payload = {})
         if notifier.listening?(name)
           instrumenter.instrument(name, payload) { yield payload if block_given? }
         else
           yield payload if block_given?
         end
 | 
        
       
     
    
      
        Extracted source (around line #20):
      
      
        
          
            | 
18
19
20
21
22
23
               | 
        start name, payload
         begin
           yield payload
         rescue Exception => e
           payload[:exception] = [e.class.name, e.message]
           raise e
 | 
        
       
     
    
      
        Extracted source (around line #164):
      
      
        
          
            | 
162
163
164
165
166
167
               | 
      def instrument(name, payload = {})
         if notifier.listening?(name)
           instrumenter.instrument(name, payload) { yield payload if block_given? }
         else
           yield payload if block_given?
         end
 | 
        
       
     
    
      
        Extracted source (around line #30):
      
      
        
          
            | 
28
29
30
31
32
33
               | 
      ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup)
 
       ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload|
         begin
           result = super
           payload[:status] = response.status
 | 
        
       
     
    
      
        Extracted source (around line #250):
      
      
        
          
            | 
248
249
250
251
252
253
               | 
        request.filtered_parameters.merge! wrapped_filtered_hash
       end
       super
     end
 
     private
 | 
        
       
     
    
      
        Extracted source (around line #18):
      
      
        
          
            | 
16
17
18
19
20
21
               | 
        # and it won't be cleaned up by the method below.
         ActiveRecord::LogSubscriber.reset_runtime
         super
       end
 
       def cleanup_view_runtime
 | 
        
       
     
    
      
        Extracted source (around line #137):
      
      
        
          
            | 
135
136
137
138
139
140
               | 
      @_response_body = nil
 
       process_action(action_name, *args)
     end
 
     # Delegates to the class' #controller_path
 | 
        
       
     
    
      
        Extracted source (around line #30):
      
      
        
          
            | 
28
29
30
31
32
33
               | 
    def process(*) #:nodoc:
       old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
       super
     ensure
       I18n.config = old_config
     end
 | 
        
       
     
    
      
        Extracted source (around line #196):
      
      
        
          
            | 
194
195
196
197
198
199
               | 
      @_env = request.env
       @_env['action_controller.instance'] = self
       process(name)
       to_a
     end
 
 | 
        
       
     
    
      
        Extracted source (around line #13):
      
      
        
          
            | 
11
12
13
14
15
16
               | 
    def dispatch(action, request)
       set_response!(request)
       super(action, request)
     end
 
     def response_body=(body)
 | 
        
       
     
    
      
        Extracted source (around line #237):
      
      
        
          
            | 
235
236
237
238
239
240
               | 
        end
       else
         lambda { |env| new.dispatch(name, klass.new(env)) }
       end
     end
   end
 | 
        
       
     
    
      
        Extracted source (around line #74):
      
      
        
          
            | 
72
73
74
75
76
77
               | 
         def dispatch(controller, action, env)
           controller.action(action).call(env)
         end
 
         def normalize_controller!(params)
 | 
        
       
     
    
      
        Extracted source (around line #74):
      
      
        
          
            | 
72
73
74
75
76
77
               | 
         def dispatch(controller, action, env)
           controller.action(action).call(env)
         end
 
         def normalize_controller!(params)
 | 
        
       
     
    
      
        Extracted source (around line #43):
      
      
        
          
            | 
41
42
43
44
45
46
               | 
          end
 
           dispatch(controller, params[:action], req.env)
         end
 
         def prepare_params!(params)
 | 
        
       
     
    
      
        Extracted source (around line #43):
      
      
        
          
            | 
41
42
43
44
45
46
               | 
          req.path_parameters = set_params.merge parameters
 
           status, headers, body = route.app.serve(req)
 
           if 'pass' == headers['X-Cascade']
             req.script_name     = script_name
 | 
        
       
     
    
      
        Extracted source (around line #30):
      
      
        
          
            | 
28
29
30
31
32
33
               | 
       def serve(req)
         find_routes(req).each do |match, parameters, route|
           set_params  = req.path_parameters
           path_info   = req.path_info
           script_name = req.script_name
 | 
        
       
     
    
      
        Extracted source (around line #30):
      
      
        
          
            | 
28
29
30
31
32
33
               | 
       def serve(req)
         find_routes(req).each do |match, parameters, route|
           set_params  = req.path_parameters
           path_info   = req.path_info
           script_name = req.script_name
 | 
        
       
     
    
      
        Extracted source (around line #817):
      
      
        
          
            | 
815
816
817
818
819
820
               | 
        req = request_class.new(env)
         req.path_info = Journey::Router::Utils.normalize_path(req.path_info)
         @router.serve(req)
       end
 
       def recognize_path(path, environment = {})
 | 
        
       
     
    
      
        Extracted source (around line #24):
      
      
        
          
            | 
22
23
24
25
26
27
               | 
     def call(env)
       status, headers, body = @app.call(env)
 
       if etag_status?(status) && etag_body?(body) && !skip_caching?(headers)
         original_body = body
 | 
        
       
     
    
      
        Extracted source (around line #25):
      
      
        
          
            | 
23
24
25
26
27
28
               | 
      case env[REQUEST_METHOD]
       when "GET", "HEAD"
         status, headers, body = @app.call(env)
         headers = Utils::HeaderHash.new(headers)
         if status == 200 && fresh?(env, headers)
           status = 304
 | 
        
       
     
    
      
        Extracted source (around line #13):
      
      
        
          
            | 
11
12
13
14
15
16
               | 
   def call(env)
     status, headers, body = @app.call(env)
 
     if env[REQUEST_METHOD] == HEAD
       [
 | 
        
       
     
    
      
        Extracted source (around line #27):
      
      
        
          
            | 
25
26
27
28
29
30
               | 
      end
 
       @app.call(env)
     end
 
     private
 | 
        
       
     
    
      
        Extracted source (around line #260):
      
      
        
          
            | 
258
259
260
261
262
263
               | 
     def call(env)
       @app.call(env)
     ensure
       session    = Request::Session.find(env) || {}
       flash_hash = env[KEY]
 | 
        
       
     
    
      
        Extracted source (around line #225):
      
      
        
          
            | 
223
224
225
226
227
228
               | 
        def context(env, app=@app)
           prepare_session(env)
           status, headers, body = app.call(env)
           commit_session(env, status, headers, body)
         end
 
 | 
        
       
     
    
      
        Extracted source (around line #220):
      
      
        
          
            | 
218
219
220
221
222
223
               | 
         def call(env)
           context(env)
         end
 
         def context(env, app=@app)
 | 
        
       
     
    
      
        Extracted source (around line #560):
      
      
        
          
            | 
558
559
560
561
562
563
               | 
     def call(env)
       status, headers, body = @app.call(env)
 
       if cookie_jar = env['action_dispatch.cookies']
         unless cookie_jar.committed?
 | 
        
       
     
    
      
        Extracted source (around line #36):
      
      
        
          
            | 
34
35
36
37
38
39
               | 
      connection.enable_query_cache!
 
       response = @app.call(env)
       response[2] = Rack::BodyProxy.new(response[2]) do
         restore_query_cache_settings(connection_id, enabled)
       end
 | 
        
       
     
    
      
        Extracted source (around line #653):
      
      
        
          
            | 
651
652
653
654
655
656
               | 
        testing = env['rack.test']
 
         response = @app.call(env)
         response[2] = ::Rack::BodyProxy.new(response[2]) do
           ActiveRecord::Base.clear_active_connections! unless testing
         end
 | 
        
       
     
    
      
        Extracted source (around line #377):
      
      
        
          
            | 
375
376
377
378
379
380
               | 
          end
         end
         @app.call(env)
       end
 
       private
 | 
        
       
     
    
      
        Extracted source (around line #29):
      
      
        
          
            | 
27
28
29
30
31
32
               | 
      result = run_callbacks :call do
         begin
           @app.call(env)
         rescue => error
         end
       end
 | 
        
       
     
    
      
        Extracted source (around line #88):
      
      
        
          
            | 
86
87
88
89
90
91
               | 
    def __run_callbacks__(callbacks, &block)
       if callbacks.empty?
         yield if block_given?
       else
         runner = callbacks.compile
         e = Filters::Environment.new(self, false, nil, block)
 | 
        
       
     
    
      
        Extracted source (around line #778):
      
      
        
          
            | 
776
777
778
779
780
781
               | 
          module_eval <<-RUBY, __FILE__, __LINE__ + 1
             def _run_#{name}_callbacks(&block)
               __run_callbacks__(_#{name}_callbacks, &block)
             end
           RUBY
         end
 | 
        
       
     
    
      
        Extracted source (around line #81):
      
      
        
          
            | 
79
80
81
82
83
84
               | 
    #   end
     def run_callbacks(kind, &block)
       send "_run_#{kind}_callbacks", &block
     end
 
     private
 | 
        
       
     
    
      
        Extracted source (around line #27):
      
      
        
          
            | 
25
26
27
28
29
30
               | 
    def call(env)
       error = nil
       result = run_callbacks :call do
         begin
           @app.call(env)
         rescue => error
 | 
        
       
     
    
      
        Extracted source (around line #73):
      
      
        
          
            | 
71
72
73
74
75
76
               | 
      prepare!
 
       response = @app.call(env)
       response[2] = ::Rack::BodyProxy.new(response[2]) { cleanup! }
 
       response
 | 
        
       
     
    
      
        Extracted source (around line #78):
      
      
        
          
            | 
76
77
78
79
80
81
               | 
    def call(env)
       env["action_dispatch.remote_ip"] = GetIp.new(env, self)
       @app.call(env)
     end
 
     # The GetIp class exists as a way to defer processing of the request data
 | 
        
       
     
    
      
        Extracted source (around line #17):
      
      
        
          
            | 
15
16
17
18
19
20
               | 
     def call(env)
       _, headers, body = response = @app.call(env)
 
       if headers['X-Cascade'] == 'pass'
         body.close if body.respond_to?(:close)
 | 
        
       
     
    
      
        Extracted source (around line #28):
      
      
        
          
            | 
26
27
28
29
30
31
               | 
        end
 
         status, headers, body = @app.call(env)
 
         if exception = env['web_console.exception']
           session = Session.from_exception(exception)
 | 
        
       
     
    
      
        Extracted source (around line #18):
      
      
        
          
            | 
16
17
18
19
20
21
               | 
     def call(env)
       app_exception = catch :app_exception do
         request = create_regular_or_whiny_request(env)
         return @app.call(env) unless request.from_whitelited_ip?
 
 | 
        
       
     
    
      
        Extracted source (around line #18):
      
      
        
          
            | 
16
17
18
19
20
21
               | 
     def call(env)
       app_exception = catch :app_exception do
         request = create_regular_or_whiny_request(env)
         return @app.call(env) unless request.from_whitelited_ip?
 
 | 
        
       
     
    
      
        Extracted source (around line #30):
      
      
        
          
            | 
28
29
30
31
32
33
               | 
     def call(env)
       @app.call(env)
     rescue Exception => exception
       if env['action_dispatch.show_exceptions'] == false
         raise exception
 | 
        
       
     
    
      
        Extracted source (around line #38):
      
      
        
          
            | 
36
37
38
39
40
41
               | 
        instrumenter.start 'request.action_dispatch', request: request
         logger.info { started_request_message(request) }
         resp = @app.call(env)
         resp[2] = ::Rack::BodyProxy.new(resp[2]) { finish(request) }
         resp
       rescue Exception
 | 
        
       
     
    
      
        Extracted source (around line #20):
      
      
        
          
            | 
18
19
20
21
22
23
               | 
         if logger.respond_to?(:tagged)
           logger.tagged(compute_tags(request)) { call_app(request, env) }
         else
           call_app(request, env)
         end
 | 
        
       
     
    
      
        Extracted source (around line #68):
      
      
        
          
            | 
66
67
68
69
70
71
               | 
     def tagged(*tags)
       formatter.tagged(*tags) { yield self }
     end
 
     def flush
 | 
        
       
     
    
      
        Extracted source (around line #26):
      
      
        
          
            | 
24
25
26
27
28
29
               | 
      def tagged(*tags)
         new_tags = push_tags(*tags)
         yield self
       ensure
         pop_tags(new_tags.size)
       end
 | 
        
       
     
    
      
        Extracted source (around line #68):
      
      
        
          
            | 
66
67
68
69
70
71
               | 
     def tagged(*tags)
       formatter.tagged(*tags) { yield self }
     end
 
     def flush
 | 
        
       
     
    
      
        Extracted source (around line #20):
      
      
        
          
            | 
18
19
20
21
22
23
               | 
         if logger.respond_to?(:tagged)
           logger.tagged(compute_tags(request)) { call_app(request, env) }
         else
           call_app(request, env)
         end
 | 
        
       
     
    
      
        Extracted source (around line #21):
      
      
        
          
            | 
19
20
21
22
23
24
               | 
    def call(env)
       env["action_dispatch.request_id"] = external_request_id(env) || internal_request_id
       @app.call(env).tap { |_status, headers, _body| headers["X-Request-Id"] = env["action_dispatch.request_id"] }
     end
 
     private
 | 
        
       
     
    
      
        Extracted source (around line #22):
      
      
        
          
            | 
20
21
22
23
24
25
               | 
      end
 
       @app.call(env)
     end
 
     def method_override(env)
 | 
        
       
     
    
      
        Extracted source (around line #18):
      
      
        
          
            | 
16
17
18
19
20
21
               | 
    def call(env)
       start_time = clock_time
       status, headers, body = @app.call(env)
       request_time = clock_time - start_time
 
       if !headers.has_key?(@header_name)
 | 
        
       
     
    
      
        Extracted source (around line #28):
      
      
        
          
            | 
26
27
28
29
30
31
               | 
          def call(env)
             LocalCacheRegistry.set_cache_for(local_cache_key, LocalStore.new)
             response = @app.call(env)
             response[2] = ::Rack::BodyProxy.new(response[2]) do
               LocalCacheRegistry.set_cache_for(local_cache_key, nil)
             end
 | 
        
       
     
    
      
        Extracted source (around line #17):
      
      
        
          
            | 
15
16
17
18
19
20
               | 
      old, env[FLAG] = env[FLAG], false
       @mutex.lock
       response = @app.call(env)
       body = BodyProxy.new(response[2]) { @mutex.unlock }
       response[2] = body
       response
 | 
        
       
     
    
      
        Extracted source (around line #120):
      
      
        
          
            | 
118
119
120
121
122
123
               | 
      end
 
       @app.call(env)
     end
   end
 end
 | 
        
       
     
    
      
        Extracted source (around line #113):
      
      
        
          
            | 
111
112
113
114
115
116
               | 
     def call(env)
       status, headers, body = @app.call(env)
       if body.respond_to?(:to_path)
         case type = variation(env)
         when 'X-Accel-Redirect'
 | 
        
       
     
    
      
        Extracted source (around line #518):
      
      
        
          
            | 
516
517
518
519
520
521
               | 
        env["ROUTES_#{routes.object_id}_SCRIPT_NAME"] = env['SCRIPT_NAME'].dup
       end
       app.call(env)
     end
 
     # Defines additional Rack env configuration that is added on each call.
 | 
        
       
     
    
      
        Extracted source (around line #165):
      
      
        
          
            | 
163
164
165
166
167
168
               | 
      env["ORIGINAL_FULLPATH"] = build_original_fullpath(env)
       env["ORIGINAL_SCRIPT_NAME"] = env["SCRIPT_NAME"]
       super(env)
     end
 
     # Reload application routes regardless if they changed or not.
 | 
        
       
     
    
      
        Extracted source (around line #17):
      
      
        
          
            | 
15
16
17
18
19
20
               | 
      old, env[FLAG] = env[FLAG], false
       @mutex.lock
       response = @app.call(env)
       body = BodyProxy.new(response[2]) { @mutex.unlock }
       response[2] = body
       response
 | 
        
       
     
    
      
        Extracted source (around line #15):
      
      
        
          
            | 
13
14
15
16
17
18
               | 
     def call(env)
       status, headers, body = @app.call(env)
       headers = HeaderHash.new(headers)
 
       if !STATUS_WITH_NO_ENTITY_BODY.include?(status.to_i) &&
 | 
        
       
     
    
      
        Extracted source (around line #88):
      
      
        
          
            | 
86
87
88
89
90
91
               | 
        env["REQUEST_PATH"] ||= [env["SCRIPT_NAME"], env[PATH_INFO]].join
 
         status, headers, body = @app.call(env)
         begin
           res.status = status.to_i
           headers.each { |k, vs|
 | 
        
       
     
    
      
        Extracted source (around line #138):
      
      
        
          
            | 
136
137
138
139
140
141
               | 
      si = servlet.get_instance(self, *options)
       @logger.debug(format("%s is invoked.", si.class.name))
       si.service(req, res)
     end
 
     ##
 | 
        
       
     
    
      
        Extracted source (around line #94):
      
      
        
          
            | 
92
93
94
95
96
97
               | 
            callback.call(req, res)
           end
           server.service(req, res)
         rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
           res.set_error(ex)
         rescue HTTPStatus::Error => ex
 | 
        
       
     
    
      
        Extracted source (around line #294):
      
      
        
          
            | 
292
293
294
295
296
297
               | 
          end
           call_callback(:AcceptCallback, sock)
           block ? block.call(sock) : run(sock)
         rescue Errno::ENOTCONN
           @logger.debug "Errno::ENOTCONN raised"
         rescue ServerError => ex
 | 
        
       
     
  
Rails.root: /home/rubys/git/awdwr/edition4/work-226-42/depot
  
Request
Parameters:
 {"id"=>"wibble"}
  
  _csrf_token: "VOTK4hVhtLsD7nJymDi+8NRL/0RAeqGDk+Ks/kVVjek="
cart_id: 1
flash: {"discard"=>["notice"], "flashes"=>{"notice"=>"Line item was successfully created."}}
session_id: "e3a1a24539de2b8c87ec6b5b12104e70" 
  
  GATEWAY_INTERFACE: "CGI/1.1"
HTTP_ACCEPT: "text/html"
HTTP_ACCEPT_ENCODING: "gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
REMOTE_ADDR: "127.0.0.1"
REMOTE_HOST: "127.0.0.1"
SERVER_NAME: "localhost"
SERVER_PROTOCOL: "HTTP/1.1"
 
Response
Headers:
 None
 
  
     
    
    
      10.2 Iteration E2: Handling Errors
      9.4 Playtime