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:
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.
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.
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.
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".
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.
Now let's write the features to make it pass.
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
Next, generate mailer with this command.
rails generate mailer Order received shipped
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
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
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.
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)) %>
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.
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
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.