読者です 読者をやめる 読者になる 読者になる

ぞえの技術めも

Ruby on Rails勉強中

【126日目】【1日20分のRailsチュートリアル】【第10章】メールプレビューのテストを作成する

Ruby on Railsチュートリアル(第3版)

今日は「10.1.2 AccountActivationsメイラーメソッド」のメールプレビューのテストを作成するところから。

10.1.2 AccountActivationsメイラーメソッド

最後に、このメールプレビューのテストも作成して、プレビューをダブルチェックできるようにします。

テスト例がRailsによって自動生成されているので、これを利用してテストを作成する。

元々あった"password_reset"のテストは今は要らないと思うのでコメントアウトした。

test/mailers/user_mailer_test.rb

  test "account_activation" do
    user = users(:michael)
    user.activation_token = User.new_token
    mail = UserMailer.account_activation(user)
    assert_equal "Account activation", mail.subject
    assert_equal [user.email], mail.to
    assert_equal ["noreply@example.com"], mail.from
    assert_match user.name,               mail.body.encoded
    assert_match user.activation_token,   mail.body.encoded
    assert_match CGI::escape(user.email), mail.body.encoded
  end

このテストがパスするには、テストファイル内のドメイン名を正しく設定する必要があります (リスト10.19)。

テストで送り元のメールアドレス(mail.from)見てるけど、メールアドレスなんてどこで設定してるんだろうと思ってた。
テスト向けにはここで設定するのかー。

config/environments/test.rb

  config.action_mailer.default_url_options = { host: 'example.com' }

これでテスト通りました。

$ bundle exec rake test:mailers
1 tests, 9 assertions, 0 failures, 0 errors, 0 skips

あとはユーザー登録を行うcreateアクションに数行追加するだけで、メイラーをアプリケーションで実際に使うことができます。

createアクションのユーザー新規作成時の処理を変更。

変更前は、ユーザーのプロファイルページ (7.4) にリダイレクトしていましたが、アカウント有効化を実装するうえでは無意味な動作なので、リダイレクト先をルートURLに変更してあります。

アカウント有効化してもらわないとプロファイルページにリダイレクトしても見れない…かな…。無意味ですね。

app/controllers/users_controller.rb

  :
  def create
    @user = User.new(user_params)
    if @user.save
      UserMailer.account_activation(@user).deliver_now
      flash[:info] = "Please check your email to activate your account."
      redirect_to root_url
    else
      render 'new'
    end
  end
  :

リスト10.21ではリダイレクト先をプロファイルページからルートURLに変更し、かつユーザーは以前のようにログインしないようになっています。
(中略)
失敗が発生するテストの行をひとまずコメントアウトしておきます (リスト10.22)。コメントアウトした部分は、10.1.4でアカウント有効化のテストをパスさせるときに元に戻します。

アプリケーションの挙動変えちゃったもんね。

test/integration/users_signup_test.rb

    :
    # assert_template 'users/show'
    # assert is_logged_in?

コメントアウトした状態でテストが通ることを確認。

$ bundle exec rake test
43 tests, 175 assertions, 0 failures, 0 errors, 0 skips

この状態で実際に新規ユーザーとして登録してみると、リダイレクトされて図10.4のようになり、リスト10.23のようなメールが生成されます。

新規ユーザーを登録してみよう。

サーバーを起動して

$ rails server -b $IP -p $PORT

適当なユーザー名とメールアドレスとパスワードでユーザー登録。

f:id:kt_zoe:20170329123442p:plain

flashメッセージ表示されました!

ただし、実際にメールが生成されるわけではないのでご注意ください。

実際にメール送信されるならメールアドレスはちゃんとしたの使わないとな、と思ってた。実際のメール送信はまだなにか必要なのか。

ここに引用したのはサーバーログに出力されたメールです。

長いから引用はしないけどサーバー起動したターミナルにメール内容出力されてた。処理は動いてそうだね。

今日の学習時間は【26分】

メイラーメソッド使う準備するの長かった…。

次は「10.1.3 アカウントを有効化する」から。

【125日目】【1日20分のRailsチュートリアル】【第10章】アカウント有効化メールのプレビューを確認する

Ruby on Railsチュートリアル(第3版)

今日は「10.1.2 AccountActivationsメイラーメソッド」のUserメイラーのプレビューファイルを更新するところから。

10.1.2 AccountActivationsメイラーメソッド

developmentサーバーを再起動してリスト10.14の設定を読み込んだら、次は10.1.2で自動生成したUserメイラーのプレビューファイルの更新が必要です。

リスト10.11で定義したaccount_activationの引数には有効な (=実在する) ユーザーオブジェクトを渡す必要があるため、リスト10.15はこのままでは動きません。

あー、そういえばメソッドに引数追加したわ。
ユーザーオブジェクトはデータベースの最初のユーザーになるようにして渡す。

リスト10.16ではuser.activation_tokenにも値を代入している点にご注目ください。リスト10.12やリスト10.13のアカウント有効化テンプレートではアカウント有効化トークンが必要なので、代入は省略できません。

アカウント有効化メールでトークンを必要とするようにしたから、ってことだよね。。。

test/mailers/previews/user_mailer_preview.rb

  # Preview this email at http://localhost:3000/rails/mailers/user_mailer/account_activation
  def account_activation
    user = User.first
    user.activation_token = User.new_token
    UserMailer.account_activation(user)
  end

ここまでできたらアカウント有効化メールのプレビューが確認できるらしい。

サーバーを起動して

$ rails server -b $IP -p $PORT

http://<ローカルアドレス>/rails/mailers/user_mailer/account_activation

にアクセス。(URLってどっから分かるの、、と思ってたらさっき編集したファイルにコメントで書かれてた)

HTML版もテキスト版も見れました。

f:id:kt_zoe:20170324123505p:plain

f:id:kt_zoe:20170324123516p:plain

今日の学習時間は【20分】

次は「10.1.2 AccountActivationsメイラーメソッド」のメールプレビューのテストを作成するところから。

【124日目】【1日20分のRailsチュートリアル】【第10章】アカウント有効化メールのビューを作成する

Ruby on Railsチュートリアル(第3版)

今日は「10.1.2 AccountActivationsメイラーメソッド」のメールにアカウント有効化リンクを追加するところから。

10.1.2 AccountActivationsメイラーメソッド

ここでは挨拶文にユーザー名を含め、カスタムの有効化リンクを追加します。
この後、Railsサーバーでユーザーをメールアドレスで検索して有効化トークンを認証できるようにしたいので、リンクにはメールアドレスとトークンを両方含めておく必要があります。

account_activations/q5lt38hQDc_959PVoo6b7A/edit?email=foo%40example.com

こんな感じでURLにトークンとメールアドレスを含めておくようにする。

ここまでできれば、リスト10.11で定義した@userインスタンス変数、editへの名前付きルート、ERBを組み合わせて、必要なリンクを作成できます (リスト10.12リスト10.13)。

○テキストビュー

app/views/user_mailer/account_activation.text.erb

Hi <%= @user.name %>,

Welcome to the Sample App! Click on the link below to activate your account:

<%= edit_account_activation_url(@user.activation_token, email: @user.email) %>

○HTMLビュー

app/views/user_mailer/account_activation.html.erb

<h1>Sample App</h1>

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

<p>
Welcome to the Sample App!Click on the link below to activate your account:
</p>

<%= link_to "Activate", edit_account_activation_url(@user.activation_token,
                                                    email: @user.email) %>

今更だけどテキストビューとHTMLビューがあるのは送り先によってテキストメール送るかHTMLメールで送るか違うからなのかな。

リスト10.12やリスト10.13で定義したテンプレートの実際の表示を簡単に確認するために、メールプレビューという裏技を使ってみましょう。

へー、そんな機能が。動作確認のために実際にメール送らないといけないのかと思ってた。

これを利用するには、アプリケーションのdevelopment環境の設定に手を加える必要があります (リスト10.14)。

元々あったconfig.action_mailer.raise_delivery_errors = falseは削除した。

config/environments/development.rb

  :
  # Don't care if the mailer can't send.
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :test
  host = 'rails-tutorial-c9-mhartl.c9.io'
  config.action_mailer.default_url_options = { host: host }
  :

今日の学習時間は【25分】

次は「10.1.2 AccountActivationsメイラーメソッド」のUserメイラーのプレビューファイルの更新をするところから。

ここまで来ると1項が長いね…。

【123日目】【1日20分のRailsチュートリアル】【第10章】UserMailerを生成してテンプレートをカスタマイズする

Ruby on Railsチュートリアル(第3版)

今日は「10.1.2 AccountActivationsメイラーメソッド」から。

10.1.2 AccountActivationsメイラーメソッド

メイラーの構成はコントローラのアクションとよく似ており、メールのテンプレートをビューと同じ要領で定義できます。
この節ではメイラーとビューを定義して、有効化トークンとメールアドレス (=有効にするアカウントのアドレス) を含むリンクをその中で使用します。

「メイラー」がそもそもよく分からないんだけど、アプリケーションでメール送るためのクラスみたいな感じかな…??

(参考)Action Mailer の基礎

メイラーは、モデルやコントローラと同様にrails generateで生成できます。

下記コマンドで「UserMailer」を生成。

$ rails generate mailer UserMailer account_activation password_reset

生成したメイラーごとに、ビューテンプレートが2つずつ生成されます。1つはテキストメール用のテンプレート、1つはHTMLメール用テンプレートです。

下記テンプレートが生成されたことを確認。

app/views/user_mailer/account_activation.text.erb

UserMailer#account_activation

<%= @greeting %>, find me in app/views/user_mailer/account_activation.text.erb

app/views/user_mailer/account_activation.html.erb

<h1>UserMailer#account_activation</h1>

<p>
  <%= @greeting %>, find me in app/views/user_mailer/account_activation.html.erb
</p>

リスト10.8には、デフォルトのfromアドレス (アプリケーション全体で共通) があります。
リスト10.9の各メソッドには宛先メールアドレスもあります。リスト10.8ではメールのフォーマットに対応するメイラーレイアウトも使用されています。

デフォルトのfromアドレスは"from@example.com"になってる。

app/mailers/application_mailer.rb

class ApplicationMailer < ActionMailer::Base
  default from: "from@example.com"
  layout 'mailer'
end

宛先メールアドレスは"to@example.org"になってるけどここは相手によって変えるとこかな…?

app/mailers/user_mailer.rb

class UserMailer < ApplicationMailer

  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.user_mailer.account_activation.subject
  #
  def account_activation
    @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.user_mailer.password_reset.subject
  #
  def password_reset
    @greeting = "Hi"

    mail to: "to@example.org"
  end
end

最初に、生成されたテンプレートをカスタマイズして、実際に有効化メールで使えるようにします (リスト10.10)。

デフォルトのfromアドレスを"noreply@example.com"に変更。

app/mailers/application_mailer.rb

  default from: "noreply@example.com"

次に、ユーザーを含むインスタンス変数を作成してビューで使えるようにし、user.emailにメール送信します (リスト10.11)。

account_activationメソッドを引数ありに変更して、user.emailにメール送信するように変更。ついでにメールの件名も設定。

app/mailers/user_mailer.rb

  def account_activation(user)
    @user = user
    mail to: user.email, subject: "Account activation"
  end

途中だけど今日はここまで。

今日の学習時間は【25分】

次は「10.1.2 AccountActivationsメイラーメソッド」のメールにアカウント有効化リンクを追加するところから。

【122日目】【1日20分のRailsチュートリアル】【第10章】アカウントの有効化トークンやダイジェストを作成する処理を追加する

Ruby on Railsチュートリアル(第3版)

今日は「10.1.1 AccountActivationsリソース」のアカウントの有効化について考えるところから。

10.1.1 AccountActivationsリソース

ユーザーが新しい登録を完了するためには必ずアカウントの有効化が必要になるのですから、有効化トークンや有効化ダイジェストはユーザーオブジェクトが作成される前に作成しておく必要があります。

before_createコールバックを使うとユーザーオブジェクト作成前に有効化トークンや有効化ダイジェストを作成できるそう。

Userモデルに有効化トークンとダイジェストを作成する処理を追加する。
ついでにメールアドレスを小文字に変換する処理もちょっと書き換える。

app/models/user.rb

class User < ActiveRecord::Base
  attr_accessor :remember_token, :activation_token
  before_save   :downcase_email
  before_create :create_activation_digest
  :
  private

    # メールアドレスをすべて小文字にする
    def downcase_email
      self.email = email.downcase
    end

    # 有効化トークンとダイジェストを作成および代入する
    def create_activation_digest
      self.activation_token  = User.new_token
      self.activation_digest = User.digest(activation_token)
    end
end

先に進む前に、サンプルデータとフィクスチャも更新し、テスト時のサンプルとユーザーを事前に有効化しておきましょう (リスト10.4リスト10.5)。

サンプルデータ更新。

db/seeds.rb

User.create!(name:  "Example User",
              :
             activated: true,
             activated_at: Time.zone.now)

99.times do |n|
              :
              activated: true,
              activated_at: Time.zone.now)
end

フィクスチャの各ユーザーに下記コードを追加。

test/fixtures/users.yml

  :
  activated: true
  activated_at: <%= Time.zone.now %>
  :

いつものようにデータベースを初期化して、サンプルデータを再度生成し直し、リスト10.4の変更を反映します。

下記を実行してサンプルデータを再度生成し直しました。

$ bundle exec rake db:migrate:reset
$ bundle exec rake db:seed

これでようやく準備的なものは終わりなのかな…??

今日の学習時間は【19分】

次は「10.1.2 AccountActivationsメイラーメソッド」から。

【121日目】【1日20分のRailsチュートリアル】【第10章】アカウント有効化のためにUserモデルに属性を追加する

Ruby on Railsチュートリアル(第3版)

今日は「10.1.1 AccountActivationsリソース」のresources行を追加するところから。

10.1.1 AccountActivationsリソース

有効化メールでは以下の形式のURLを使用します。

edit_account_activation_url(activation_token, ...)

これは、editアクションへの名前付きルートが必要になるということです。そのためのresources行を追加します (リスト10.1)。

ほぅ…そうなのか。。。

よく分かってないけど下記を追加。

config/routes.rb

  resources :account_activations, only: [:edit]

続いて、一意の有効化トークンがユーザー有効化に必要です。

パスワードのときと同じように有効化トークンを使えばいいってことかな。。。

以下のマイグレーションコマンドラインで実行して図10.1のデータモデルを追加すると、3つの属性が新しく追加されます。

  • activation_digest
  • activated
  • activated_at

の3つの属性を追加。

$ rails generate migration add_activation_to_users activation_digest:string activated:boolean activated_at:datetime
      invoke  active_record
      create    db/migrate/20170313024742_add_activation_to_users.rb

admin 属性 (リスト9.50) の時と同様に、activated属性のデフォルトの論理値をfalseにします (リスト10.2)。

さっき生成したファイルを下記のように修正してマイグレーション実行。

db/migrate/[timestamp]_add_activation_to_users.rb

    add_column :users, :activated, :boolean, default: false
$ bundle exec rake db:migrate
== 20170313024742 AddActivationToUsers: migrating =============================
-- add_column(:users, :activation_digest, :string)
   -> 0.0006s
-- add_column(:users, :activated, :boolean, {:default=>false})
   -> 0.0035s
-- add_column(:users, :activated_at, :datetime)
   -> 0.0004s
== 20170313024742 AddActivationToUsers: migrated (0.0049s) ====================

まだ中途半端だけど今日はここまで。

今日の学習時間は【20分】

次は「10.1.1 AccountActivationsリソース」のアカウントの有効化について考えるとこから。

【120日目】【1日20分のRailsチュートリアル】【第10章】AccountActivationsリソースを生成する

Ruby on Railsチュートリアル(第3版)

今日は「第10章 アカウント有効化とパスワード再設定」から。

今日から10章!

第10章 アカウント有効化とパスワード再設定

アカウントの有効化 (アクティベーション: 新規ユーザーのメールアドレスが有効であることを確認する機能) と、パスワードの再設定 (パスワードを忘れてしまったユーザー向けの機能) を実装することにします。

「アカウントの有効化」ってなんだろう、と思ってた。なるほどね。

10.1 アカウントの有効化

おおよその流れは、有効化トークンやダイジェストをユーザーと関連付け、ユーザーにメールを送信し、そのメールにはトークンを含むリンクを記載しておき、ユーザーがそのリンクをクリックすると有効化できるようになる、というものです。

ほぅほぅ。新規登録するときによくある流れだけどその裏側が理解できるってことか。

それではいつものように、Gitで新機能用のトピックブランチを作成しましょう。
10.3で説明したとおり、アカウントの有効化とパスワードの再設定では、メールの設定部分に共通するところがありますので、その部分を両機能に適用してからGitのmasterにマージします。

10章用にブランチ作成する。

$ git checkout master
$ git checkout -b account-activation-password-reset

10.1.1 AccountActivationsリソース

この作業に必要なデータ (有効化トークンや有効化ステータスなど) をUserモデルに追加することにします。

ひとまずAccountActivationsコントローラを下記コマンドで生成。

$ rails generate controller AccountActivations --no-test-framework
  :
      create  app/controllers/account_activations_controller.rb
      invoke  erb
      create    app/views/account_activations
      invoke  helper
      create    app/helpers/account_activations_helper.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/account_activations.coffee
      invoke    scss
      create      app/assets/stylesheets/account_activations.scss

上のコマンドでは、テストを生成しないというオプションを指定していることにご注目ください。
著者はコントローラのテストよりも統合テスト (10.1.4) の方が望ましいと考えているので、コントローラのテストを生成しないようにしているのです。

ほぅ…。何が違うのか分かってないけど今はいいか。。。

中途半端だけど今日はここまで。

今日の学習時間は【21分】

次は「10.1.1 AccountActivationsリソース」のresources行を追加するところから。