Agile Web Development with Rails, Edition 4

13.2 Iteration H2: Integration Tests 12.4 Playtime

13.1 Iteration H1: Email Notifications

Create a mailer

rails generate mailer OrderNotifier received shipped
      create  app/mailers/order_notifier.rb
      invoke  erb
      create    app/views/order_notifier
      create    app/views/order_notifier/received.text.erb
      create    app/views/order_notifier/shipped.text.erb
      invoke  test_unit
      create    test/functional/order_notifier_test.rb

Edit development configuration

edit config/environments/development.rb
Depot::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb
 
  # In the development environment your application's code is reloaded on
  # every request. This slows down response time but is perfect for development
  # since you don't have to restart the web server when you make code changes.
  config.cache_classes = false
 
  # Log error messages when you accidentally call methods on nil.
  config.whiny_nils = true
 
  # Show full error reports and disable caching
  config.consider_all_requests_local       = true
  config.action_controller.perform_caching = false
 
  # Don't care if the mailer can't send
  config.action_mailer.raise_delivery_errors = false
 
  # Don't actually send emails
  config.action_mailer.delivery_method = :test
  #
  # Alternate configuration example, using gmail:
  #   config.action_mailer.delivery_method = :smtp
  #   config.action_mailer.smtp_settings = {
  #     address:        "smtp.gmail.com",
  #     port:           587, 
  #     domain:         "domain.of.sender.net",
  #     authentication: "plain",
  #     user_name:      "dave",
  #     password:       "secret",
  #     enable_starttls_auto: true
  #   } 
 
  # Print deprecation notices to the Rails logger
  config.active_support.deprecation = :log
 
  # Only use best-standards-support built into browsers
  config.action_dispatch.best_standards_support = :builtin
 
  # Raise exception on mass assignment protection for Active Record models
  config.active_record.mass_assignment_sanitizer = :strict
 
  # Log the query plan for queries taking more than this (works
  # with SQLite, MySQL, and PostgreSQL)
  config.active_record.auto_explain_threshold_in_seconds = 0.5
 
  # Do not compress assets
  config.assets.compress = false
 
  # Expands the lines which load the assets
  config.assets.debug = true
end

Tailor the from address

edit app/mailers/order_notifier.rb
class OrderNotifier < ActionMailer::Base
  default from: 'Sam Ruby <depot@example.com>'
 
  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.order_notifier.received.subject
  #
  def received
    @greeting = "Hi"
 
    mail to: "to@example.org"
  end
 
  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.order_notifier.shipped.subject
  #
  def shipped
    @greeting = "Hi"
 
    mail to: "to@example.org"
  end
end

Tailor the confirm receipt email

edit app/views/order_notifier/received.text.erb
Dear <%= @order.name %>
 
Thank you for your recent order from The Pragmatic Store.
 
You ordered the following items:
 
<%= render @order.line_items -%>
 
We'll send you a separate e-mail when your order ships.

Text partial for the line items

edit app/views/line_items/_line_item.text.erb
<%= sprintf("%2d x %s",
            line_item.quantity,
            truncate(line_item.product.title, length: 50)) %>

Get the order, sent the confirmation

edit app/mailers/order_notifier.rb
class OrderNotifier < ActionMailer::Base
  default from: 'Sam Ruby <depot@example.com>'
 
  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.order_notifier.received.subject
  #
  def received(order)
    @order = order
 
    mail to: order.email, subject: 'Pragmatic Store Order Confirmation'
  end
 
  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.order_notifier.shipped.subject
  #
  def shipped(order)
    @order = order
 
    mail to: order.email, subject: 'Pragmatic Store Order Shipped'
  end
end

Invoke mailer from the controller

edit app/controllers/orders_controller.rb
  def create
    @order = Order.new(params[:order])
    @order.add_line_items_from_cart(@cart)
 
    respond_to do |format|
      if @order.save
        Cart.destroy(session[:cart_id])
        session[:cart_id] = nil
        OrderNotifier.received(@order).deliver
        format.html { redirect_to store_url, notice: 
          'Thank you for your order.' }
        format.json { render json: @order, status: :created,
          location: @order }
      else
        format.html { render action: "new" }
        format.json { render json: @order.errors,
          status: :unprocessable_entity }
      end
    end
  end

Tailor the confirm shipped email (this time in HTML)

edit app/views/order_notifier/shipped.html.erb
<h3>Pragmatic Order Shipped</h3>
<p>
  This is just to let you know that we've shipped your recent order:
</p>
 
<table>
  <tr><th colspan="2">Qty</th><th>Description</th></tr>
<%= render @order.line_items -%>
</table>

Review HTML partial for the line items

edit app/views/line_items/_line_item.html.erb
<% if line_item == @current_item %>
<tr id="current_item">
<% else %>
<tr>
<% end %>
  <td><%= line_item.quantity %>&times;</td>
  <td><%= line_item.product.title %></td>
  <td class="item_price"><%= number_to_currency(line_item.total_price) %></td>
</tr>

Update the test case

edit test/functional/order_notifier_test.rb
require 'test_helper'
 
class OrderNotifierTest < ActionMailer::TestCase
  test "received" do
    mail = OrderNotifier.received(orders(:one))
    assert_equal "Pragmatic Store Order Confirmation", mail.subject
    assert_equal ["dave@example.org"], mail.to
    assert_equal ["depot@example.com"], mail.from
    assert_match /1 x Programming Ruby 1.9/, mail.body.encoded
  end
 
  test "shipped" do
    mail = OrderNotifier.shipped(orders(:one))
    assert_equal "Pragmatic Store Order Shipped", mail.subject
    assert_equal ["dave@example.org"], mail.to
    assert_equal ["depot@example.com"], mail.from
    assert_match /<td>1&times;<\/td>\s*<td>Programming Ruby 1.9<\/td>/,
      mail.body.encoded
  end
 
end
rake db:test:load
ruby -I test test/functional/order_notifier_test.rb
Run options: 
 
# Running tests:
 
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
..
 
Finished tests in 0.490757s, 4.0753 tests/s, 20.3767 assertions/s.
 
2 tests, 10 assertions, 0 failures, 0 errors, 0 skips

13.2 Iteration H2: Integration Tests 12.4 Playtime