acts_as_authenticatedの使い方 - その3

前回はautheticated_mailerによって生成されるActionMailerの設定が完成したが、authenticated_mailerは、ユーザ登録時に、ユーザが登録したemailアドレスにメールを送信し、そのメールを参照したユーザが記載されているURLにアクセスして初めてユーザ登録を完了するプロセスになる。これを実現するためには、前々回のauthenticatedジェネレータが生成したusersテーブルにactivation_codeとactivated_atという2つのカラムを追加する必要がある。

class AddActivationToUserTable < ActiveRecord::Migration
  def self.up
    add_column :users, :activation_code, :string, :limit => 40
    add_column :users, :activated_at, :datetime
  end

  def self.down
    remove_column :users, :activation_code
    remove_column :users, :activated_at
  end
end

上記のコードをdb/migrate/002_add_activation_to_user_table.rbという名前で保存し、rake db:migrateを実行する。
app/models/user_notifier.rbでは、前回ActionMailのテストのためにsignup_notificationメソッドの一部をzzzzzという仮コードに変更してあった。これは上のようにactivation_codeというカラムがテーブルに追加されたので元の状態に戻す。

#    @body[:url]  = "http://localhost:3000/account/activate/zzzzzzzzzz"
    @body[:url]  = "http://localhost:3000/account/activate/#{user.activation_code}"

ユーザアクティベーション用のコードをmodels/user.rbに追加する。
以下のコードをUserクラス定義の最初の部分、たとえばbefore_save :encrypted_passwdの次に追加する。

  # User Activation
  before_create :make_activation_code

続けて、以下のコードを既存のself.authenticationメソッドの定義と入れ換える。

  # Authenticates a user by their login name and unencrypted password.  Returns the user or nil.
  def self.authenticate(login, password)
    # User Activation - hide records with a nil activated_at
    u = find :first, :conditions => ['login = ? and activated_at IS NOT NULL', login]
    u && u.authenticated?(password) ? u : nil
  end

新規で追加となるメソッドは以下の通り。

  # User Activation - Activates the user in the database.
  def activate
    @activated = true
    update_attributes(:activated_at => Time.now.utc, :activation_code => nil)
  end

  # User Activation - Returns true if the user has just been activated.
  def recently_activated?
    @activated
  end

最後部のprotectedメソッドにも1つメソッドを新規で追加する。

    # User Activation
    def make_activation_code
      self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
    end

次にapp/controllers/account_controller.rbを修正する。
まず、既存のsignupメソッドを以下のコードと置き換える。

  # User Activation - need replace signup
  def signup
    @user = User.new(params[:user])
    return unless request.post?
    @user.save!
    redirect_to(:action => 'signup_notification')
    flash[:notice] = "Thanks for signing up! Please check you mail box."
  rescue ActiveRecord::RecordInvalid
    render :action => 'signup'
  end

そして以下のactivateメソッドを追加する。

  # User Activation
  def activate
    @user = User.find_by_activation_code(params[:id])
    if @user and @user.activate
      self.current_user = @user
      flash[:notice] = "Your account has been activated."
    else
      flash[:notice] = "Invalid activation code."
    end
  end

app/views/accountでは、以下の内容で2つのビューテンプレートを作成しておく。1つが、activate.rhtmlで、もう1つがsignup_notification.rhtmlとする。flashのメッセージを表示する簡単なもので、2つのファイルとも内容は同じでよい。

<%= flash[:notice] %>

これでacts_as_authenticatedおよびメールによるユーザ認証コードの設定は一通り完了となる。localhost:3000/accountにアクセスし、ユーザを登録すると、指定したメールアドレスに確認用メールが配信されること、そこに記載されたURLにアクセスするとユーザ登録が完了することを確認してほしい。