Rails6 ユーザ登録完了後に確認メールを送信する

# 目的

- Rails6ユーザ登録完了後に登録時に入力したメールアドレスに確認メールを送信する方法をまとめる

# 作業期待値

- ユーザ登録時に入力されるユーザのメールアドレスを使用して登録完了メールを送信する。
- メールの送信機能を優先して実装するため、ユーザ登録時の情報保存とメール送信のタイミングは加味しない。

# 作業前にちょっと聞いてほしいこと

- 下記の記事を読んでいただけると若干理解が早いかもしれない。
    - [Rails6 アプリからGmailのメールサーバからメールを送信する ローカル環境編](https://qiita.com/miriwo/items/06d7d69aff47fd02fbc1)
    - [Rails6 アプリからメールを送信する デプロイ環境編](https://qiita.com/miriwo/items/46a58bd92f74f0dc74d8)
- 直指定したメールアドレスにRails6のアプリからテストメールが送信できる状況を前提として説明する。

# 結論

- メールアドレスはメソッドの引数として与える。

# 作業概要

1. `アプリ名/app/mailers`直下にあるメーラー設定ファイルの`mailer.rb`内のメソッドに引数を指定
1. `mailer.rb`内のメソッド内で引数を変数に格納する処理を追記
1. メール送信トリガコードでメソッドを指定する際に引数を指定

# 作業詳細

1. `アプリ名/app/mailers`直下にあるメーラー設定ファイルの`mailer.rb`内のメソッドに引数を指定
    1. 筆者の場合の記載をする。
        1. `アプリ名/app/mailers`直下にあるメーラー設定ファイルの`notice_mailer.rb`を開く。
        1. 下記のように修正する。

            ```ruby
            class NoticeMailer < ApplicationMailer

              # Subject can be set in your I18n file at config/locales/en.yml
              # with the following lookup:
              #
              #   en.notice_mailer.greeting.subject
              #
              def greeting
                @greeting = "Hi"
                mail to: "miriwo0517@gmail.com"
              end
            end
            ```

            ↓修正

            ```ruby
            class NoticeMailer < ApplicationMailer

              # Subject can be set in your I18n file at config/locales/en.yml
              # with the following lookup:
              #
              #   en.notice_mailer.greeting.subject
              #
              def greeting(user)
                @greeting = "Hi"
                @user = user
                mail to: "miriwo0517@gmail.com"
              end
            end
            ```
 
1. `mailer.rb`内のメソッド内で引数を変数に格納する処理を追記
    1. 筆者の場合の記載をする。
        1. `アプリ名/app/mailers`直下にあるメーラー設定ファイルの`notice_mailer.rb`を開く。
        1. 下記のように修正する。

            ```ruby
            class NoticeMailer < ApplicationMailer

              # Subject can be set in your I18n file at config/locales/en.yml
              # with the following lookup:
              #
              #   en.notice_mailer.greeting.subject
              #
              def greeting(user)
                @greeting = "Hi"
                @user = user
                mail to: "miriwo0517@gmail.com"
              end
            end
            ```

            ↓修正

            ```ruby
            class NoticeMailer < ApplicationMailer

              # Subject can be set in your I18n file at config/locales/en.yml
              # with the following lookup:
              #
              #   en.notice_mailer.greeting.subject
              #
              def greeting(user)
                @greeting = "Hi"
                @user = user
                mail to: @user.email
              end
            end
            ``` 

1. メール送信トリガコードでメソッドを指定する際に引数を指定
    1. 筆者の場合の記載をする。
        1. メール送信トリガコードのメソットの指定部分で引数を受け取れるようにする。
        1. ユーザ登録時にメールを送信したいので`アプリ名/app/controllers`直下にある`users_controller.rb`の`create`アクションの修正内容を下記に記載する。

        ```ruby
        def create
          @user = User.new(name: params[:name], email: params[:email], 
          password_digest: params[:password])
          if @user.save
            # flash[:notice] = "登録完了"
            session[:user_id] = @user.id
            redirect_to("/users/#{@user.id}")
          else
            # flash[:notice] = "登録失敗"
            render ("users/new")
          end
        end
        ```

        ↓修正

        ```ruby
        def create
          @user = User.new(name: params[:name], email: params[:email], 
          password_digest: params[:password])
          if @user.save
            #flash[:notice] = "登録完了"
            session[:user_id] = @user.id
            NoticeMailer.greeting(@user).deliver_now
            redirect_to("/users/#{@user.id}")
          else
           #flash[:notice] = "登録失敗"
           render ("users/new")
          end
        end
        ```

# 付録

- 今回の処理に関係するメーラーの設定ファイルやユーザ新規登録のビューファイルなど内容を下記に記載する。
- notice_mailer.rb

```ruby
class NoticeMailer < ApplicationMailer

  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.notice_mailer.greeting.subject
  #
  def greeting(user)
    @greeting = "Hi"
    @user = user
    mail to: @user.email
  end
end
```

- development.rb

```ruby
Rails.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

  # Do not eager load code on boot.
  config.eager_load = false

  # Show full error reports.
  config.consider_all_requests_local = true

  # Enable/disable caching. By default caching is disabled.
  # Run rails dev:cache to toggle caching.
  if Rails.root.join('tmp', 'caching-dev.txt').exist?
    config.action_controller.perform_caching = true
    config.action_controller.enable_fragment_cache_logging = true

    config.cache_store = :memory_store
    config.public_file_server.headers = {
      'Cache-Control' => "public, max-age=#{2.days.to_i}"
    }
  else
    config.action_controller.perform_caching = false

    config.cache_store = :null_store
  end

  # Store uploaded files on the local file system (see config/storage.yml for options).
  config.active_storage.service = :local

  # Don't care if the mailer can't send.
  # config.action_mailer.perform_caching = false
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    :enable_starttls_auto => true,
    :address => 'smtp.gmail.com',
    :port => '587',
    :domain => 'smtp.gmail.com',
    :authentication => 'plain',
    :user_name => 'miriwo.rails@gmail.com',
    :password => 'smppyvjbfzhweyxx'
  }

  # Print deprecation notices to the Rails logger.
  config.active_support.deprecation = :log

  # Raise an error on page load if there are pending migrations.
  config.active_record.migration_error = :page_load

  # Highlight code that triggered database queries in logs.
  config.active_record.verbose_query_logs = true

  # Debug mode disables concatenation and preprocessing of assets.
  # This option may cause significant delays in view rendering with a large
  # number of complex assets.
  config.assets.debug = true

  # Suppress logger output for asset requests.
  config.assets.quiet = true

  # Raises error for missing translations.
  # config.action_view.raise_on_missing_translations = true

  # Use an evented file watcher to asynchronously detect changes in source code,
  # routes, locales, etc. This feature depends on the listen gem.
  config.file_watcher = ActiveSupport::EventedFileUpdateChecker
end
```

- production.rb

```ruby
Rails.application.configure do
  # Settings specified here will take precedence over those in config/application.rb.

  # Code is not reloaded between requests.
  config.cache_classes = true

  # Eager load code on boot. This eager loads most of Rails and
  # your application in memory, allowing both threaded web servers
  # and those relying on copy on write to perform better.
  # Rake tasks automatically ignore this option for performance.
  config.eager_load = true

  # Full error reports are disabled and caching is turned on.
  config.consider_all_requests_local       = false
  config.action_controller.perform_caching = true

  # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
  # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
  # config.require_master_key = true

  # Disable serving static files from the `/public` folder by default since
  # Apache or NGINX already handles this.
  config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?

  # Compress CSS using a preprocessor.
  # config.assets.css_compressor = :sass

  # Do not fallback to assets pipeline if a precompiled asset is missed.
  config.assets.compile = false

  # Enable serving of images, stylesheets, and JavaScripts from an asset server.
  # config.action_controller.asset_host = 'http://assets.example.com'

  # Specifies the header that your server uses for sending files.
  # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
  # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX

  # Store uploaded files on the local file system (see config/storage.yml for options).
  config.active_storage.service = :local

  # Mount Action Cable outside main process or domain.
  # config.action_cable.mount_path = nil
  # config.action_cable.url = 'wss://example.com/cable'
  # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]

  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
  # config.force_ssl = true

  # Use the lowest log level to ensure availability of diagnostic information
  # when problems arise.
  config.log_level = :debug

  # Prepend all log lines with the following tags.
  config.log_tags = [ :request_id ]

  # Use a different cache store in production.
  # config.cache_store = :mem_cache_store

  # Use a real queuing backend for Active Job (and separate queues per environment).
  # config.active_job.queue_adapter     = :resque
  # config.active_job.queue_name_prefix = "eveyDayStudy_production"

  config.action_mailer.perform_caching = false
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.perform_deliveries = true
  config.action_mailer.smtp_settings = {
  :user_name => ENV['SENDGRID_USERNAME'],
  :password => ENV['SENDGRID_PASSWORD'],
  :domain => 'herokuapp.com',
  :address => 'smtp.sendgrid.net',
  :port => 587,
  :authentication => :plain,
  :enable_starttls_auto => true

  # Ignore bad email addresses and do not raise email delivery errors.
  # Set this to true and configure the email server for immediate delivery to raise delivery errors.
  # config.action_mailer.raise_delivery_errors = false

  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
  # the I18n.default_locale when a translation cannot be found).
  config.i18n.fallbacks = true

  # Send deprecation notices to registered listeners.
  config.active_support.deprecation = :notify

  # Use default logging formatter so that PID and timestamp are not suppressed.
  config.log_formatter = ::Logger::Formatter.new

  # Use a different logger for distributed setups.
  # require 'syslog/logger'
  # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')

  if ENV["RAILS_LOG_TO_STDOUT"].present?
    logger           = ActiveSupport::Logger.new(STDOUT)
    logger.formatter = config.log_formatter
    config.logger    = ActiveSupport::TaggedLogging.new(logger)
  end

  # Do not dump schema after migrations.
  config.active_record.dump_schema_after_migration = false

  # Inserts middleware to perform automatic connection switching.
  # The `database_selector` hash is used to pass options to the DatabaseSelector
  # middleware. The `delay` is used to determine how long to wait after a write
  # to send a subsequent read to the primary.
  #
  # The `database_resolver` class is used by the middleware to determine which
  # database is appropriate to use based on the time delay.
  #
  # The `database_resolver_context` class is used by the middleware to set
  # timestamps for the last write to the primary. The resolver uses the context
  # class timestamps to determine how long to wait before reading from the
  # replica.
  #
  # By default Rails will store a last write timestamp in the session. The
  # DatabaseSelector middleware is designed as such you can define your own
  # strategy for connection switching and pass that into the middleware through
  # these configuration options.
  # config.active_record.database_selector = { delay: 2.seconds }
  # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
  # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
end

```

- posts_controller.rb

```ruby
class PostsController < ApplicationController
  def index
    NoticeMailer.greeting.deliver_now
    @posts = Post.where(user_id: @current_user.id)
  end

  def show
    @post = Post.find_by(id: params[:id])
  end

  def new
    @post = Post.new
  end

  def create
    @post = Post.new(content: params[:content], study_time: params[:'study_time'], today_study_time: params[:'study_time'], hash_tag: params[:hash_tag], user_id: @current_user.id)
    if @post.save
      # flash[:notice] = "保存完了"
      redirect_to("/posts/#{@post.id}")
    else
      # flash[:notice] = "保存失敗"
      render ("posts/new")
    end
  end

  def edit_form
    @post = Post.find_by(id: params[:id])
  end

  def edit
    @post = Post.find_by(id: params[:id])
    @post.content = params[:content]
    @post.hash_tag = params[:hash_tag]
    @post.save
    redirect_to("/posts/#{@post.id}")
  end

  def achievement
    @post = Post.find_by(id: params[:id])

  end

  def destroy
    @post = Post.find_by(id: params[:id])
    @post.destroy
    redirect_to("/posts/index/#{@post.user_id}")
  end

  def update
    @post = Post.find_by(id: params[:id])
    @post.today_study_time = params[:study_time].to_f
    @post.save
    @post.study_time += @post.today_study_time
    @post.save
    redirect_to("/posts/#{@post.id}")
  end

  def tweet_content
    @post = Post.find_by(id: params[:id])
  end
end
```

- `アプリ名/app/mailers`のapplication_mailer.rb

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

- `アプリ名/app/views/notice_mailer`のgreeting.html.erb

```ruby
<p>このメールはテストメールです。</p>

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

- `アプリ名/app/views/notice_mailer`のgreeting.text.erb

```
このメールはテストメールです。

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

- `アプリ名/test/mailers`のnotice_mailer_test.rb

```ruby
require 'test_helper'

class NoticeMailerTest < ActionMailer::TestCase
  test "greeting" do
    mail = NoticeMailer.greeting
    assert_equal "Greeting", mail.subject
    assert_equal ["to@example.org"], mail.to
    assert_equal ["from@example.com"], mail.from
    assert_match "Hi", mail.body.encoded
  end

end
```

- `アプリ名/test/mailers/previews`のnotice_mailer_preview.rb

```ruby
# Preview all emails at http://localhost:3000/rails/mailers/notice_mailer
class NoticeMailerPreview < ActionMailer::Preview

  # Preview this email at http://localhost:3000/rails/mailers/notice_mailer/greeting
  def greeting
    NoticeMailer.greeting
  end

end
```