The Simplified Go Food Web App - Iteration 6
Sending Email & Deployment
Sending Email
The Requirements
It's your product manager again. He is happy with your progress so far. But as usual, he comes up with more features to develop. This time, he asks you to:
- Write a feature that will send a confirmation email when an Order is received by our app
- Write a feature that will send a confirmation email when an Order is shipped
Email Spec
For sending emails, Rails provides us with ActionMailer. However, to test ActionMailer we need to install more gem.
group :test do
# -cut-
gem 'email_spec'
end
Then run bundle install.
Spec Helper
require "email_spec"
require "email_spec/rspec"
Add these lines to your spec_helper.rb file.
require File.expand_path("../../config/environment", __FILE__)
require 'spec_helper'
And modify your rails_helper.rb file, change the order of these lines so they look like this.
Mailer Macros
module MailerMacros
def last_email
ActionMailer::Base.deliveries.last
end
def reset_email
ActionMailer::Base.deliveries = []
end
end
We will setup some macros for our Mailer specs. Create a file named "mailer_macros.rb" in folder "spec/support/" and fill it with these lines.
Mailer Specs
require 'rails_helper'
describe OrderMailer do
describe "received message" do
let(:order) { create(:order) }
let(:mail) { OrderMailer.received(order) }
it "sends confirmation email when order is received" do
expect(mail.subject).to eq("Go Food Order Confirmation")
expect(mail.to).to eq([order.email])
expect(mail.from).to eq(["go.scholarship.kolla@gmail.com"])
end
end
describe "shipped message" do
let(:order) { create(:order) }
let(:mail) { OrderMailer.shipped(order) }
it "sends confirmation email when order is shipped" do
expect(mail.subject).to eq("Go Food Order Shipped")
expect(mail.to).to eq([order.email])
expect(mail.from).to eq(["go.scholarship.kolla@gmail.com"])
end
end
end
After setting up all the necessary things, we will now write our mailer specs. Create a new folder "spec/mailers/" and add these lines to a file named "order_mailer_spec.rb".
Orders Controller Spec
describe OrdersController do
# -cut-
describe 'POST #create' do
context "with valid attributes" do
# -cut-
it "sends order confirmation email" do
post :create, params: { order: attributes_for(:order) }
expect {
OrderMailer.received((assigns(:order))).deliver
}.to change { ActionMailer::Base.deliveries.count }.by(1)
end
# -cut-
end
# -cut-
end
# -cut-
end
Lastly, we need to modify our Orders controller spec to test if it sends an email after creating an order. Add "sends order confirmation email" spec before "redirects to store index page" spec in "POST #create" block.
Make It Pass
Now let's write the features to make it pass.
Configuring SMTP
Let's start by configuring our SMTP settings. Change your "development.rb" file to look like this.
Rails.application.configure do
#-cut-
# Send mailer
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: "smtp.gmail.com",
port: 587,
authentication: "plain",
user_name: "go.scholarship.kolla",
password: "Kolaboras1",
enable_starttls_auto: true
}
config.action_mailer.raise_delivery_errors = true
config.action_mailer.perform_deliveries = true
#-cut-
end
Generate Mailer
Next, generate mailer with this command.
rails generate mailer Order received shipped
Modifying Order Mailer
Then we need to modify our Order mailer.
class OrderMailer < ApplicationMailer
default from: "Go Scholarship Kolla <go.scholarship.kolla@gmail.com>"
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.order_mailer.received.subject
#
def received(order)
@order = order
mail to: order.email, subject: 'Go Food Order Confirmation'
end
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.order_mailer.shipped.subject
#
def shipped(order)
@order = order
mail to: order.email, subject: 'Go Food Order Shipped'
end
end
Modifying Order Mailer
Then we need to modify our Order mailer.
class OrderMailer < ApplicationMailer
default from: "Go Scholarship Kolla <go.scholarship.kolla@gmail.com>"
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.order_mailer.received.subject
#
def received(order)
@order = order
mail to: order.email, subject: 'Go Food Order Confirmation'
end
# Subject can be set in your I18n file at config/locales/en.yml
# with the following lookup:
#
# en.order_mailer.shipped.subject
#
def shipped(order)
@order = order
mail to: order.email, subject: 'Go Food Order Shipped'
end
end
Email Templates (1)
Lastly, we will change our email templates. First, we create a file named "app/views/mailer/recevied.text.erb"
Dear <%= @order.name %>
Thank you for your recent Go Food order. You ordered the following items:
<%= render @order.line_items %>
We'll send you a separate e-mail when your order ships.
Email Templates (2)
Then, we write partial for line_item in "app/views/line_items/_line_item.text.erb"
<%= sprintf("%2d x %s",
line_item.quantity,
truncate(line_item.food.name, length: 50)) %>
Email Templates (3)
We can also use html template for our mailer. Write this one in a file named "app/views/mailer/shipped.html.erb"
<h3>Go Food Order Shipped</h3>
<p>
This is just to let you know that we've shipped your recent Go Food order:
</p>
<table>
<tr>
<th colspan="2">Qty</th>
<th>Description</th>
</tr>
<%= render @order.line_items %>
</table>
For the partial, it will automatically use "_line_item.html.erb" partial that we wrote back then.
Modifying Orders Controller
To actually send the mail, we need to modify our Orders controller.
class OrdersController < ApplicationController
# -cut-
# POST /orders
# POST /orders.json
def create
@order = Order.new(order_params)
@order.add_line_items(@cart)
respond_to do |format|
if @order.save
Cart.destroy(session[:cart_id])
session[:cart_id] = nil
OrderMailer.received(@order).deliver!
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
# -cut-
end
Play Around
Now your specs will all pas. Play around with your app. Try to create an order and fill your email address as the buyer's email. See if your mail is delivered to your inbox.
Afterward, don't forget to commit your progress.
Deployment
The Simplified Go Food Web App - Iteration 6
By qblfrb
The Simplified Go Food Web App - Iteration 6
- 220