[Ruby on Rails]sorceryによる認証 – (3)メールによるアクティベーション

2015.05.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

以前の記事に引き続きsorceryによる認証についてです。今回はアカウントの作成時にメールを送信し、リンクをクリックしたらアカウントを有効化する、アクティベーションを実装してみました。

なお今回はsorceryで認証ができるアプリに、機能を追加する形で実装していきます。予め以下などを参考にemail、passwordでアカウントを登録できるアプリを作成しておいてください。
公式チュートリアル
以前の記事

アクティベーションの画面フロー

今回作成する機能のイメージを掴みやすくするため、画面のスクリーンショットを遷移順に貼っておきます。

1.アカウントの作成

sorcery_activation_1_first

「New User」をクリックし、アカウント作成画面を表示します。

2.アカウント作成

sorcery_activation_2_create_user

「Email」「Password」を入力して登録します。

3.アカウント登録完了

sorcery_activation_3_create_success

登録されたアカウントが一覧に表示されます。ここまではアクティベーションの有無に関わらず(画面上は)同じ動きとなります。

4.メールによるアクティベーション前でのログイン

sorcery_activation_4_login_failed

この時点でアクティベーションのためのメールが送られている筈ですが、敢えてそのメールを見る前にログインしてみます。するとログインは失敗します。

5.アクティベーションのためのメール

sorcery_activation_5_activation_mail

アカウント作成時に入力したメールアドレスに、アクティベーションを行う為のメールが送られてきます。「To login to the site,・・・」以降のリンクをクリックすると、次のアクティベーション成功の画面が表示されます。

6.アクティベーション成功

sorcery_activation_6_activation_success

メールのリンクをクリックすると、アクティベーションが行われ、成功した旨のメッセージが表示されます。

7.アクティベーション成功メール

sorcery_activation_7_activation_success_mail

上記と同時に、アクティベーションが成功した旨のメールも送られてきます。

8.ログイン成功

sorcery_activation_8_login_success

アクティベーション後にログインすると、ログインが成功します。

アプリケーションの実装

では実装についてです。今回も公式チュートリアルをなぞりましたが、幾つか追加したり変更した手順もありますので合わせて紹介したいと思います。

1.「user_activation」サブモジュールのインストール

sorceryは追加可能な機能を、それぞれサブモジュールの形で提供しています。今回はアクティベーションを行うのに「user_activation」サブモジュールが必要なので、これをインストールします。以下のコマンドを実行してください。

$ rails g sorcery:install user_activation  --only-submodules

以下のようなマイグレーションファイルが作成されます。

class SorceryUserActivation < ActiveRecord::Migration
  def self.up
    add_column :users, :activation_state, :string, :default => nil
    add_column :users, :activation_token, :string, :default => nil
    add_column :users, :activation_token_expires_at, :datetime, :default => nil

    add_index :users, :activation_token
  end

  def self.down
    remove_index :users, :activation_token

    remove_column :users, :activation_token_expires_at
    remove_column :users, :activation_token
    remove_column :users, :activation_state
  end
end

マイグレーションを実行してDBに反映します。

$ rake db:migrate

またsorceryの定義ファイルに、使用するサブモジュールとして「user_activation」が追加されていることを確認してください(無ければ追加してください)。

config/initializers/sorcery.rb
Rails.application.config.sorcery.submodules = [:user_activation, ・・・

2.ActionMailerの作成

アクティベーションのメールを送信するため、RailsのActionMailerを使用します。以下のコマンドで、ActionMailerのテンプレートを作成します。

$ rails g mailer UserMailer activation_needed_email activation_success_email

sorceryの定義ファイルにアクティベーションで使用するActionMailerとして、上記で作成したUserMailerを定義します。

config/initializers/sorcery.rb
  config.user_config do |user|
    (中略)
    user.user_activation_mailer = UserMailer
    (中略)
  end

アクティベーション時のメールと、アクティベーション成功時のメールを定義します。

app/mailers/user_mailer.rb
def activation_needed_email(user)
  @user = user
  @url  = "http://0.0.0.0:3000/users/#{user.activation_token}/activate"
  mail(:to => user.email,
       :subject => "Welcome to My Awesome Site")
end

def activation_success_email(user)
  @user = user
  @url  = "http://0.0.0.0:3000/login"
  mail(:to => user.email,
       :subject => "Your account is now activated")
end
app/views/user_mailer/activation_needed_email.text.erb
Welcome to example.com, <%= @user.email %>
===============================================

You have successfully signed up to example.com,
your email is: <%= @user.email %>.

To login to the site, just follow this link: <%= @url %>.

Thanks for joining and have a great day!
app/views/user_mailer/activation_success_email.text.erb
Congratz, <%= @user.email %>
===============================================

You have successfully activated your example.com account,
your email is: <%= @user.email %>.

To login to the site, just follow this link: <%= @url %>.

Thanks for joining and have a great day!

公式のチュートリアルではユーザ名(user.username)を参照していましたが、今回はユーザ名は保持していないため、全てメールアドレス(email)に変更しています。またテキスト形式でのフォーマットのみ定義しているため、HTML形式のフォーマットファイル(app/views/user_mailer/〜.html.erb)は削除しました。

3.アクティベーションを行うアクションを定義

アクティベーションを行うアクションを、コントローラに定義します。

app/controllers/users_controller.rb
skip_before_filter :require_login, :only => [:index, :new, :create, :activate]

def activate
  if (@user = User.load_from_activation_token(params[:id]))
    @user.activate!
    redirect_to(login_path, :notice => 'User was successfully activated.')
  else
    not_authenticated
  end
end

ルーティングも上記アクションを呼び出せるように変更します。

config/routes.rb
resources :users do
  member do
    get :activate
  end
end

4.ActionMailerの定義

公式のチュートリアルはここまでの手順しか載っていませんが、実際にメールを送信するにはSMTPの定義が必要です。今回はgmailを使用したので、以下の様な定義を行いました。2段階認証を使用している場合、gmailのアカウントのパスワードと、アプリケーション固有のパスワードの2つを定義することに注意してください。

config/environments/development.rb
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.smtp_settings = {
      :enable_starttls_auto => true,
      :address => 'smtp.gmail.com',
      :port => '587',
      :domain => 'smtp.gmail.com',
      :authentication => 'plain',
      :user_name => 'ユーザ名',
      :password => 'パスワード',
      :password => 'アプリケーション固有のパスワード'
  }

まとめ

以上のように非常に簡単にアクティベーションを実装することができました。メールの送信にはActionMailerを使用するなどRailsとの親和性も高く、使いやすいように思います。

参考サイト

以下のサイトを参考にさせて頂きました。ありがとうございました。
Simple Password Authentication
User Activation
RailsのActionMailerでメールを送信する(Gmail経由)
Googleで2段階認証を使っているときにRailsのActionMailerでGmailを使う方法