13
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ruby on Rails チュートリアル 機能拡張3(フォロワーの通知)

Last updated at Posted at 2018-01-13

#Ruby on Rails チュートリアルについて
Ruby on Railsを勉強したいというと、まず紹介される有名なRailsのチュートリアル。
内容はハードですが、無料でRailsによるWebアプリケーション開発を楽しく学べます。

Ruby on Rails チュートリアル
https://railstutorial.jp/

#Sample Appの拡張
チュートリアルの最後には、作成したSampleAppの拡張機能についていくつかのヒントが記載されています。
その中の以下の機能を順に実装していきます(途中で挫折するかも。。。)。

  1. ユーザー検索
  2. マイクロポスト検索
  3. フォロワーの通知
  4. 返信機能
  5. メッセージ機能

#フォロワーの通知
今回は、3つ目のフォロワーの通知の実装を行います。
フォロワーの通知では、新しく誰かがフォロワーした時とフォロワーの誰かがフォローを解除した時に、対象のユーザーにメールで通知するようにします。
また、ユーザーごとに通知設定を変更できるようにします。

前回(マイクロポスト検索)はこちら

##環境と準備
今回は、特に新たにインストールする必要のあるモジュールはありません。

モジュール バージョン
Rails 5.1.2
Ruby 2.3.1

##実装
まずフォロー時、フォロー解除時のメール通知機能を追加し、その後で通知設定の変更を実装します。

フォロー/フォロー解除時のメールの送信ということで、まずRelationship用のMailerを作成します。
コマンドラインで以下のコマンドを実行します。
rails g mailer RelationshipMailer
すると、railsが色々作ってくれるので、まずはMailer、次にメールの本文の作成という順番でいじってきます。

RelationshipMailerには、フォロー/フォロー解除時のメールを送るメソッドを作成します。

app/mailers/relationship_mailer.rb
class RelationshipMailer < ApplicationMailer

  def follow_notification(user, follower)
    @user = user
    @follower = follower
    mail to: user.email, subject: "#{@follower.name} started following you"
  end

  def unfollow_notification(user, follower)
    @user = user
    @follower = follower
    mail to: user.email, subject: "#{@follower.name} unfollowed you"
  end
end

送信先アドレスとメールの題名を指定しています。
次に、メールの本文を作成します。
本文を記載するファイルは、app/views/relationship_mailerの下に作成します。
html形式とtext形式の両方を作成しましたが、今回はhtml形式のもののみご紹介します。

app/views/relationship_mailer/follow_notification.html.erb
<h1>Sample App</h1>

<p>Hi <%= @user.name %>,</p>

<p>
  <%= @follower.name %> started following you!
  Click on the link below to check your followers:
</p>

<%= link_to "Your follower list",
      followers_user_url(@user) %>
app/views/relationship_mailer/unfollow_notification.html.erb
<h1>Sample App</h1>

<p>Hi <%= @user.name %>,</p>

<p>
  <%= @follower.name %> unfollowed you.
  Click on the link below to check your followers:
</p>

<%= link_to "Your follower list",
      followers_user_url(@user) %>

メールができあがったので、プレビューファイルを更新して、ブラウザでメールの文面を確認できるようにします。

test/mailers/previews/relationship_mailer_preview.rb
class RelationshipMailerPreview < ActionMailer::Preview

  def follow_notification
    user = User.first
    follower = User.second
    RelationshipMailer.follow_notification(user, follower)
  end

  def unfollow_notification
    user = User.first
    follower = User.second
    RelationshipMailer.unfollow_notification(user, follower)
  end
end

プレビュー結果
followメール.png
unfollowメール.png

メールの文面の確認ができたので、実際にメールを送信する処理をRelationshipクラスに追加します。

app/models/relationshp.rb
~
省略
~
def Relationship.send_follow_email(user, follower)
  RelationshipMailer.follow_notification(user, follower).deliver_now
end

def Relationship.send_unfollow_email(user, follower)
  RelationshipMailer.unfollow_notification(user, follower).deliver_now
end
~
省略
~

そして、最後にフォローとフォロー解除時の処理(follow/unfollow)から上記の処理をコールするようにして、メール通知機能は完了です。

app/models/user.rb
def follow(other_user)
  active_relationships.create(followed_id: other_user.id)
  Relationship.send_follow_email(other_user, self)
end

def unfollow(other_user)
  active_relationships.find_by(followed_id: other_user.id).destroy
  Relationship.send_unfollow_email(other_user, self)
end

次に、通知設定の切り替えを実装します。
まず、下記のコマンドでusersテーブルに通知設定のON/OFFを設定するためのカラムを追加します。
rails g migration add_follow_notification_to_users follow_notification:boolean

migraionファイルを確認すると、以下のようになっています。

db/migrate/20180113140506_add_follow_notification_to_user.rb
class AddFollowNotificationToUser < ActiveRecord::Migration[5.1]
  def change
    add_column :users, :follow_notification, :boolean
  end
end

デフォルトで値をfalseにしたいので、add_columnの行に以下のようにdefault属性を追加します。
add_column :users, :follow_notification, :boolean, default:false
そして、dbにマイグレート/リセットし、シードファイルを再度読み込みます。
rails db:migrate:reset
rails db:seed

次に、viewの実装をします。
通知設定をユーザーが行う場合、新規ユーザー登録とプロフィール編集時に行えるようにすべきです。
今回は、_form.html.erbを両者からrenderするようにしていたため、修正は一箇所のみです。

app/views/users/_form.html.erb
~
省略
~
<%= f.label :follow_notification, class:"checkbox inline" do %>
    <%= f.check_box :follow_notification %>
    <span>Send email when other users follow or unfollow you</span>
<% end %>

<%= f.submit yield(:button_text), class: "btn btn-primary" %>

見た目はこんな感じになります。
edit画面.png


次にUsersControllerのuser_paramメソッドを以下のように変更します。

app/controllers/users_controller.rb
def user_params
  params.require(:user).permit(:name, :email,
                               :password, :password_confirmation,
                               :follow_notification)
end

これは、通知の設定/変更を許可するためです。

最後の最後に、Userクラスのfollow/unfollowメソッドを書き直して完成です。

app/models/user.rb
def follow(other_user)
  active_relationships.create(followed_id: other_user.id)
  if other_user.follow_notification
    Relationship.send_follow_email(other_user, self)
  end
end

def unfollow(other_user)
  active_relationships.find_by(followed_id: other_user.id).destroy
  if other_user.follow_notification
    Relationship.send_unfollow_email(other_user, self)
  end
end

##テスト
最後にテストについて記載します。
今回は、メールの内容と通知設定の両方をテストします。

まずメールの内容ですが、題名、送信先、送信元、フォローした/フォローされたユーザーのユーザー名をチェックします。
テストは、relationship_mailer.rb作成時に自動作成された、relationship_mailer_test.rbに記載します。

test/mailers/relationship_mailer_test.rb
class RelationshipMailerTest < ActionMailer::TestCase
  test "follow_notification" do
    user = users(:hoge)
    follower = users(:fuga)
    mail = RelationshipMailer.follow_notification(user, follower)
    assert_equal "#{follower.name} started following you", mail.subject
    assert_equal [user.email], mail.to
    assert_equal ["noreply@example.com"], mail.from
    assert_match user.name, mail.body.encoded
    assert_match follower.name, mail.body.encoded
  end

  test "unfollow_notification" do
    user = users(:hoge)
    follower = users(:fuga)
    mail = RelationshipMailer.unfollow_notification(user, follower)
    assert_equal "#{follower.name} unfollowed you", mail.subject
    assert_equal [user.email], mail.to
    assert_equal ["noreply@example.com"], mail.from
    assert_match user.name, mail.body.encoded
    assert_match follower.name, mail.body.encoded
  end
end

次の通知設定は、通知する設定の際にメールが送信されること、通知しない設定の際にメールが送信されないことをチェックします。
テストは、チュートリアル内で作成した、following_test.rbに追記します。

test/integration/following_test.rb
~
省略
~
test "should send follow notification email" do
    post relationships_path, params: {followed_id: @other.id}
    assert_equal 1, ActionMailer::Base.deliveries.size
  end

  test "should not send follow notification email" do
    not_notify = users(:hogehoge)
    post relationships_path, params: {followed_id: not_notify.id}
    assert_equal 0, ActionMailer::Base.deliveries.size
  end

  test "should send unfollow notification email" do
    @user.follow(@other)
    relationship = @user.active_relationships.find_by(followed_id: @other.id)
    delete relationship_path(relationship)
    assert_equal 2, ActionMailer::Base.deliveries.size # follow email and unfollow email
  end

  test "should not send unfollow notification email" do
    not_notify = users(:hogehoge)
    @user.follow(not_notify)
    relationship = @user.active_relationships.find_by(followed_id: not_notify.id)
    delete relationship_path(relationship)
    assert_equal 0, ActionMailer::Base.deliveries.size
  end
~
省略
~

上記のテストでは、fixtureで@other のみ通知設定ONにし、setupにActionMailer::Base.deliveries.clearを追記し、毎回送信メール数を初期化しています。

両方のテストが通ったことを確認して終了です。

#最後に
私はまだRails歴2週間ほどであり、以上の実装/テストも私の環境で動いたということに過ぎません。
修正点や指摘等ございましたら、ぜひコメントお願いいたします。

#参考記事
フォロワーの通知では、下記のページを参考にさせていただきました。

Action Mailerの基礎
https://railsguides.jp/action_mailer_basics.html

13
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
19

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?