Agile Web Development with Rails, Edition 5

14.3 Playtime 14.1 Iteration I1: Email Notifications

14.2 Iteration I2: Connecting to a Slow Payment Processor with Active Job

edit lib/pago.rb
require 'ostruct'
class Pago
  def self.make_payment(order_id:,
                        payment_method:,
                        payment_details:)
 
    case payment_method
    when :check
      Rails.logger.info "Processing check: " +
        payment_details.fetch(:routing).to_s + "/" + 
        payment_details.fetch(:account).to_s
    when :credit_card
      Rails.logger.info "Processing credit_card: " +
        payment_details.fetch(:cc_num).to_s + "/" + 
        payment_details.fetch(:expiration_month).to_s + "/" + 
        payment_details.fetch(:expiration_year).to_s
    when :po
      Rails.logger.info "Processing purchase order: " +
        payment_details.fetch(:po_num).to_s
    else
      raise "Unknown payment_method #{payment_method}"
    end
    sleep 3 unless Rails.env.test?
    Rails.logger.info "Done Processing Payment"
    OpenStruct.new(succeeded?: true)
  end
end
edit app/models/order.rb
require 'active_model/serializers/xml'
require 'pago'
 
class Order < ApplicationRecord
  include ActiveModel::Serializers::Xml
  enum pay_type: {
    "Check"          => 0, 
    "Credit card"    => 1, 
    "Purchase order" => 2
  }
  has_many :line_items, dependent: :destroy
  # ...
  validates :name, :address, :email, presence: true
  validates :pay_type, inclusion: pay_types.keys
  def add_line_items_from_cart(cart)
    cart.line_items.each do |item|
      item.cart_id = nil
      line_items << item
    end
  end
 
  def charge!(pay_type_params)
    payment_details = {}
    payment_method = nil
 
    case pay_type
    when "Check"
      payment_method = :check
      payment_details[:routing] = pay_type_params[:routing_number]
      payment_details[:account] = pay_type_params[:account_number]
    when "Credit card"
      payment_method = :credit_card
      month,year = pay_type_params[:expiration_date].split(//)
      payment_details[:cc_num] = pay_type_params[:credit_card_number]
      payment_details[:expiration_month] = month
      payment_details[:expiration_year] = year
    when "Purchase order"
      payment_method = :po
      payment_details[:po_num] = pay_type_params[:po_number]
    end
 
    payment_result = Pago.make_payment(
      order_id: id,
      payment_method: payment_method,
      payment_details: payment_details
    )
 
    if payment_result.succeeded?
      OrderMailer.received(self).deliver_later
    else
      raise payment_result.error
    end
  end
end
rails generate job charge_order
      invoke  test_unit
      create    test/jobs/charge_order_job_test.rb
      create  app/jobs/charge_order_job.rb
edit app/jobs/charge_order_job.rb
class ChargeOrderJob < ApplicationJob
  queue_as :default
 
  def perform(order,pay_type_params)
 
    order.charge!(pay_type_params)
 
  end
end
edit app/controllers/orders_controller.rb
class OrdersController < ApplicationController
  include CurrentCart
  before_action :set_cart, only: [:new, :create]
  before_action :ensure_cart_isnt_empty, only: :new
  before_action :set_order, only: [:show, :edit, :update, :destroy]
 
  # GET /orders
  # GET /orders.json
  def index
    @orders = Order.all
  end
 
  # GET /orders/1
  # GET /orders/1.json
  def show
  end
 
  # GET /orders/new
  def new
    @order = Order.new
  end
 
  # GET /orders/1/edit
  def edit
  end
 
  # POST /orders
  # POST /orders.json
  def create
    @order = Order.new(order_params)
    @order.add_line_items_from_cart(@cart)
 
    respond_to do |format|
      if @order.save
        Cart.destroy(session[:cart_id])
        session[:cart_id] = nil
        session[:order_id] = @order.id
        ChargeOrderJob.perform_later(@order,pay_type_params.to_h)
        format.html { redirect_to store_index_url, notice: 
          'Thank you for your order.' }
        format.json { render :show, status: :created,
          location: @order }
      else
        format.html { render :new }
        format.json { render json: @order.errors,
          status: :unprocessable_entity }
      end
    end
  end
 
  # PATCH/PUT /orders/1
  # PATCH/PUT /orders/1.json
  def update
    respond_to do |format|
      if @order.update(order_params)
        format.html { redirect_to @order, notice: 'Order was successfully updated.' }
        format.json { render :show, status: :ok, location: @order }
      else
        format.html { render :edit }
        format.json { render json: @order.errors, status: :unprocessable_entity }
      end
    end
  end
 
  # DELETE /orders/1
  # DELETE /orders/1.json
  def destroy
    @order.destroy
    respond_to do |format|
      format.html { redirect_to orders_url, notice: 'Order was successfully destroyed.' }
      format.json { head :no_content }
    end
  end
 
  private
    # Use callbacks to share common setup or constraints between actions.
    def set_order
      @order = Order.find(params[:id])
    end
 
    # Never trust parameters from the scary internet, only allow the white list through.
    def order_params
      params.require(:order).permit(:name, :address, :email, :pay_type)
    end
  #...
 
  private
     def ensure_cart_isnt_empty
       if @cart.line_items.empty?
         redirect_to store_index_url, notice: 'Your cart is empty'
       end
     end
 
    # START: pay_type_params
      
    def pay_type_params
      if order_params[:pay_type] == "Credit Card"
        params.require(:order).permit(:credit_card_number, :expiration_date)
      elsif order_params[:pay_type] == "Check"
        params.require(:order).permit(:routing_number, :account_number)
      elsif order_params[:pay_type] == "Purchase Order"
        params.require(:order).permit(:po_number)
      else
        {}
      end
    end
 
    # END: pay_type_params
end
edit test/system/orders_test.rb
require "application_system_test_case"
 
 
class OrdersTest < ApplicationSystemTestCase
  include ActiveJob::TestHelper
    
  setup do
    @order = orders(:one)
  end
 
  test "visiting the index" do
    visit orders_url
    assert_selector "h1", text: "Orders"
  end
 
  test "creating a Order" do
    visit orders_url
    click_on "New Order"
 
    fill_in "Address", with: @order.address
    fill_in "Email", with: @order.email
    fill_in "Name", with: @order.name
    fill_in "Pay Type", with: @order.pay_type
    click_on "Create Order"
 
    assert_text "Order was successfully created"
    click_on "Back"
  end
 
  test "updating a Order" do
    visit orders_url
    click_on "Edit", match: :first
 
    fill_in "Address", with: @order.address
    fill_in "Email", with: @order.email
    fill_in "Name", with: @order.name
    fill_in "Pay Type", with: @order.pay_type
    click_on "Update Order"
 
    assert_text "Order was successfully updated"
    click_on "Back"
  end
 
  test "destroying a Order" do
    visit orders_url
    page.accept_confirm do
      click_on "Destroy", match: :first
    end
 
    assert_text "Order was successfully destroyed"
  end
 
  test "check routing number" do
 
    LineItem.delete_all
    Order.delete_all
 
    visit store_index_url
 
    visit store_index_url
 
    first('.catalog li').click_on 'Add to Cart'
 
    click_on 'Checkout'
 
    fill_in 'order_name', with: 'Dave Thomas'
    fill_in 'order_address', with: '123 Main Street'
    fill_in 'order_email', with: 'dave@example.com'
 
    assert_no_selector "#order_routing_number"
 
    select 'Check', from: 'pay_type'
 
 
    assert_selector "#order_routing_number"
 
    fill_in "Routing #", with: "123456"
    fill_in "Account #", with: "987654"
 
    perform_enqueued_jobs do
      click_button "Place Order"
    end
 
    orders = Order.all
    assert_equal 1, orders.size
 
    order = orders.first
 
    assert_equal "Dave Thomas",      order.name
    assert_equal "123 Main Street",  order.address
    assert_equal "dave@example.com", order.email
    assert_equal "Check",            order.pay_type
    assert_equal 1, order.line_items.size
 
    mail = ActionMailer::Base.deliveries.last
    assert_equal ["dave@example.com"],                 mail.to
    assert_equal 'Sam Ruby <depot@example.com>',       mail[:from].value
    assert_equal "Pragmatic Store Order Confirmation", mail.subject
 
  end 
end
rake test:system
Run options: --seed 634
 
# Running:
 
E
 
Error:
ProductsTest#test_creating_a_Product:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
    test/system/products_test.rb:14:in `block in <class:ProductsTest>'
 
Error:
ProductsTest#test_creating_a_Product:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/products_test.rb:13
 
E
 
Error:
ProductsTest#test_destroying_a_Product:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
    test/system/products_test.rb:42:in `block in <class:ProductsTest>'
 
Error:
ProductsTest#test_destroying_a_Product:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/products_test.rb:41
 
E
 
Error:
ProductsTest#test_updating_a_Product:
Net::ReadTimeout: Net::ReadTimeout
    test/system/products_test.rb:28:in `block in <class:ProductsTest>'
 
Error:
ProductsTest#test_updating_a_Product:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/products_test.rb:27
 
E
 
Error:
ProductsTest#test_visiting_the_index:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
    test/system/products_test.rb:9:in `block in <class:ProductsTest>'
 
Error:
ProductsTest#test_visiting_the_index:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/products_test.rb:8
 
E
 
Error:
OrdersTest#test_creating_a_Order:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
    test/system/orders_test.rb:21:in `block in <class:OrdersTest>'
 
Error:
OrdersTest#test_creating_a_Order:
Net::ReadTimeout: Net::ReadTimeout
 
 
bin/rails test test/system/orders_test.rb:20
 
E
 
Error:
OrdersTest#test_updating_a_Order:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
    test/system/orders_test.rb:35:in `block in <class:OrdersTest>'
 
Error:
OrdersTest#test_updating_a_Order:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/orders_test.rb:34
 
E
 
Error:
OrdersTest#test_destroying_a_Order:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
    test/system/orders_test.rb:49:in `block in <class:OrdersTest>'
 
Error:
OrdersTest#test_destroying_a_Order:
Net::ReadTimeout: Net::ReadTimeout
 
 
bin/rails test test/system/orders_test.rb:48
 
E
 
Error:
OrdersTest#test_visiting_the_index:
Net::ReadTimeout: Net::ReadTimeout
    test/system/orders_test.rb:16:in `block in <class:OrdersTest>'
 
Error:
OrdersTest#test_visiting_the_index:
Net::ReadTimeout: Net::ReadTimeout
 
 
bin/rails test test/system/orders_test.rb:15
 
E
 
Error:
OrdersTest#test_check_routing_number:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
    test/system/orders_test.rb:66:in `block in <class:OrdersTest>'
 
Error:
OrdersTest#test_check_routing_number:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/orders_test.rb:59
 
E
 
Error:
CartsTest#test_visiting_the_index:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
    test/system/carts_test.rb:9:in `block in <class:CartsTest>'
 
Error:
CartsTest#test_visiting_the_index:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/carts_test.rb:8
 
E
 
Error:
CartsTest#test_creating_a_Cart:
Net::ReadTimeout: Net::ReadTimeout
    test/system/carts_test.rb:14:in `block in <class:CartsTest>'
 
Error:
CartsTest#test_creating_a_Cart:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/carts_test.rb:13
 
E
 
Error:
CartsTest#test_destroying_a_Cart:
Net::ReadTimeout: Net::ReadTimeout
    test/system/carts_test.rb:34:in `block in <class:CartsTest>'
 
Error:
CartsTest#test_destroying_a_Cart:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/carts_test.rb:33
 
E
 
Error:
CartsTest#test_updating_a_Cart:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
    test/system/carts_test.rb:24:in `block in <class:CartsTest>'
 
Error:
CartsTest#test_updating_a_Cart:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/carts_test.rb:23
 
E
 
Error:
LineItemsTest#test_visiting_the_index:
ActiveRecord::RecordNotFound: Couldn't find LineItem with 'id'=980190962
    test/system/line_items_test.rb:5:in `block in <class:LineItemsTest>'
 
Error:
LineItemsTest#test_visiting_the_index:
Net::ReadTimeout: Net::ReadTimeout
 
 
bin/rails test test/system/line_items_test.rb:8
 
E
 
Error:
LineItemsTest#test_updating_a_Line_item:
ActiveRecord::RecordNotFound: Couldn't find LineItem with 'id'=980190962
    test/system/line_items_test.rb:5:in `block in <class:LineItemsTest>'
 
Error:
LineItemsTest#test_updating_a_Line_item:
Net::ReadTimeout: Net::ReadTimeout
 
 
bin/rails test test/system/line_items_test.rb:25
 
E
 
Error:
LineItemsTest#test_creating_a_Line_item:
ActiveRecord::RecordNotFound: Couldn't find LineItem with 'id'=980190962
    test/system/line_items_test.rb:5:in `block in <class:LineItemsTest>'
 
Error:
LineItemsTest#test_creating_a_Line_item:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/line_items_test.rb:13
 
E
 
Error:
LineItemsTest#test_destroying_a_Line_item:
ActiveRecord::RecordNotFound: Couldn't find LineItem with 'id'=980190962
    test/system/line_items_test.rb:5:in `block in <class:LineItemsTest>'
 
Error:
LineItemsTest#test_destroying_a_Line_item:
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
  (Driver info: chromedriver=2.33.506092 (733a02544d189eeb751fe0d7ddca79a0ee28cce4),platform=Linux 4.4.0-98-generic x86_64)
 
 
bin/rails test test/system/line_items_test.rb:37
 
 
 
Finished in 1816.855111s, 0.0094 runs/s, 0.0000 assertions/s.
17 runs, 0 assertions, 0 failures, 17 errors, 0 skips
rake test
Run options: --seed 60558
 
# Running:
 
.........................................
 
Finished in 1.360123s, 30.1443 runs/s, 65.4353 assertions/s.
41 runs, 89 assertions, 0 failures, 0 errors, 0 skips

14.3 Playtime 14.1 Iteration I1: Email Notifications