Rails+Deviseで会員登録完了をGoogleAnalyticsのコンバージョンとして測定する

Railsで認証するならとりあえずDeviseですよね。

Deviseで会員登録完了（この記事中では確認メールからURLをクリックして認証済みになるまで）をコンバージョンとしてGoogle Analyticsで測定する方法を説明します。

## 背景

デジタルマーケティングと連動させるのでアクセス解析ツール上で数字を把握する必要があったため。

## 画面遷移の説明

Deviseで特にカスタマイズせず普通に本人確認込みの認証すると以下の流れになります。

1. sign_in(ログイン画面）
1. sign_up(登録フォーム）
1. sign_in(本人確認メール送信してログイン画面に戻る）
1. メールを開いて本人確認のリンクをクリック
1. confirmation?confirmation_token=xx(本人確認の実施）
1. sign_in(本人確認完了後に302リダイレクトされてログイン画面へ）

今回はこの最後の2つ「confirmation」と「sign_in」に手を入れて対応しました。

最後のsign_in内でconfirmation?のリファラーを取得してコンバージョンを測定すると楽かなと思ったのですが、以下の2パターンがあるためこの方法では正しくコンバージョンを測定できません。

1. 本人確認のメールを開いてリンクをクリックして、その直後のURL「confirmation?confirmation_token=xx」では302リダイレクトされてしまうのでこのリファラー情報が取れない。
1. 有効期限切れなどの間違った本人確認URLでも「sign_in」ページに転送される。

302リダイレクト先をthanksページにする方法もありますが、ただでさえ長い認証フローにページを追加してこれ以上ややこしくしたくないので採用しませんでした。

## Deviseのカスタマイズ

Deviseには極力手を加えたくないのですが、ピンポイントで[Devise::ConfirmationsController](https://github.com/plataformatec/devise/blob/master/app/controllers/devise/confirmations_controller.rb)だけ拡張します。

ルーティングにDeviseのconfirmationsに独自のコントローラーを利用するよう指定します。

```rb:routes.rb
  devise_for :users, path: "auth", controllers: {
    confirmations: 'myapp/confirmations'
  }
```

下のコードがconfirmationsで利用する独自のコントローラーです。認証成功になる状況であれば flash[:user_confirmed] をtrueにしています。

```rb:app/controllers/myapp/confirmations_controller.rb
class Myapp::ConfirmationsController < Devise::ConfirmationsController
  def show
    super{|resource|
      flash[:user_confirmed] = resource.errors.empty?
    }
  end
end
```

続いてどうしてこのコードで動作するのか説明します。以下Deviseのコードです。

```rb:master/app/controllers/devise/confirmations_controller.rb
  # GET /resource/confirmation?confirmation_token=abcdef
  def show
    self.resource = resource_class.confirm_by_token(params[:confirmation_token])
    yield resource if block_given?

    if resource.errors.empty?
      set_flash_message!(:notice, :confirmed)
      respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
    else
      respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
    end
  end
```

見てみるとブロックが与えられていれば（block_given?）、引数にモデル指定して与えられたブロックを実行する仕組みです。

そしてモデルにエラーが無ければ（resource.errors.empty?）本人確認に成功した後のコードが実行されます。

そのため本人確認が成功する条件でのみ実行する処理をさせたい場合には以下のように書くことができます。シンプルでしょ？

```rb
super{|r|
 xxxx if r.errors.empty?
}
```

# sign_inページの変更

本人確認に成功していれば flash[:user_confirmed] = true になります。

これを使って本人確認成功直後であればpageviewに会員登録成功を意味するURL('/ga/complete_a_new_account_registration')を指定します。

```html+erb
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-xxxxxxxx-xx', 'auto');
  <% if flash[:user_confirmed] %>
    ga('send', 'pageview', '/ga/complete_a_new_account_registration');
  <% else %>
    ga('send', 'pageview');
  <% end %>
</script>
```

ウェブサイト側での対応は以上です。

あとはGoogle Analytics上のコンバージョンの到達ページにこの'/ga/complete_a_new_account_registration'を指定するとコンバージョンの取得ができるようになります。

## ページを追加せずにコンバージョンを測定できる

これでページを1つも追加する事なく、Deviseを使った認証の流れの中でGoogle Analyticsのコンバージョンを測定できるようになりました。

ただでさえ煩雑になりがちな認証フローをデジタルマーケティングに対応させるためとは言え、さらに複雑にしてしまうとサイト利用者のテンションが下がってしまいますよね。

コンバージョン以外の数字でもRails+Deviseで作られたサイトであれば記事中の仕組みを使って同様に取得できますのでシンプルに測定を済ませたい方におすすめです。

質問などあればコメント欄にお願いします。