ユーザ登録をするに当たって、多くのサービスは以下の流れになるかと思います。
・メールアドレスとパスワードを入力してもらう
・仮登録のメールを送る
・メールアドレスが本人であることを確認して本登録のURLをクリックしてもらう
・有効期限内で、適切なURLであれば登録が完了する

 その際に必要となるワンタイムのトークンURLについて紹介したいと思います。下のサイトを参考にしました。

モデル

 まずはワンタイムトークンを生成するモデルを作ります。

$ rails g model token

 ユーザモデルとトークンモデルのアソシエーションを書きます。トークンには有効期限を設けるので、期限内に本登録を行わなかった場合などの理由で何度か生成する可能性がありますので『has_many』にしています。『has_one』にしてトークンを生成(ユーザ登録時)する度に上書きする方法でもいいかもしれません。

models/user.rb

class User < ActiveRecord::Base
  has_many :tokens
end

models/token.rb

class Token < ActiveRecord::Base
  belongs_to :user
end

db/migrate/20140823231004_create_tokens.rb

class CreateTokens < ActiveRecord::Migration
  def change
    create_table :tokens do |t|
      t.references :user, null: false     # ユーザと紐付け
      t.string :uuid, null: false         # トークン
      t.datetime :expired_at, null: false 
      t.timestamps
    end
    add_index :tokens, :user_id
  end
end

ルーティング

 本登録するためのトークンURLをルーティングする。これでhttp://ドメイン/users/token/{uuid}にアクセスできる。

resources :users do
  # ログイントークン
  get 'token/:uuid', :to => 'users#token'
end

コントローラー(トークン生成)

 トークンの生成は『new』アクションでメールアドレスとパスワードを入力した後に、『create』アクションで生成してActionMailerなどでユーザのメールアドレスに送付します。トークンの生成には『SecureRandom.uuid』を用いる。作成する際のポイントは以下のとおり。プログラムには冗長なところがあります。

・有効期限を設ける(今回は24時間としている)
・本登録する前にもう一度仮登録した場合は前のトークンを使えなくする
・ユーザ登録しようとしたメールアドレスが登録済みか調べる

controllers/users_controller.rb

def create
  # 入力したメールアドレスのユーザが存在するか調べる
  tmp_user = User.find_by_email(user_params[:email])

  if tmp_user && tmp_user.created
    # ユーザ作成済み
    flash.alert = "入力されたメールアドレスは登録済みです。"
    redirect_to :action => 'regist'

  elsif tmp_user
    # ユーザは既にあるが、本登録していない。一度トークンを全て使えなくする(するならhas_oneで上書く方がいいかもしれないが)
    @user = tmp_user
    Token.all.each do |token|
      # 有効期限を変更する
      token.update_attributes!(expired_at: Time.now)
    end
    # 新しいトークン生成
    @token = SecureRandom.uuid
    # 有効期限は24時間
    @user.tokens.create!(uuid: @token, expired_at: 24.hours.since)
    # メール通知(ActionMailer)
    @mail = TestMailer.user_create_mail(@user,@token).deliver
    # 仮登録成功ページヘ
    redirect_to :action => 'tmp'
  else
    @user = User.new(user_params)
    @user.created = false

    if @user.save
      # トークン生成
      @token = SecureRandom.uuid
      @user.tokens.create!(uuid: @token, expired_at: 24.hours.since)
      # メール通知
      @mail = TestMailer.user_create_mail(@user,@token).deliver
      redirect_to :action => 'tmp'
    else
      render 'new'
    end
  end
end

コントローラー(本登録)

 トークンURLにアクセスした時に有効期限内であれば本登録を行う。また、Userモデルに『:created』パラメータを用意して、本登録済みかどうかに用いている。

・ワンタイムトークンURLが有効なのは1回だけ。

def token
  # 有効期限の確認
  token = Token.find_by_uuid!(params[:uuid])
  # 有効期限を過ぎていないか確認
  if token && token.expired_at > Time.now
    # 2回目アクセスできないように更新
    token.update_attributes!(expired_at: Time.now)
    @user = token.user
    @user.update_attributes!(created: true)
    # 登録完了メール通知
    flash.now.alert = "本登録が完了しました"
    @mail = TestMailer.user_complete_mail(@user).deliver
    # ログイン画面へ
    redirect_to :login
  else
    # トークンがない、もしくは2回目のアクセス -> 失敗を通知、ユーザ登録ページのリンクを貼る
    if token && token.user.created
      redirect_to :login, alert: "入力されたメールアドレスは本登録が完了しています。"
    else
      redirect_to :action => 'new', alert: "仮登録の有効期限が切れている。もしくは、URLが適切ではありません。"
    end
  end
end

メーラー(仮登録)

 ActionMailerのテンプレートには以下のサンプルのような感じで書けば良いでしょう。

ご利用いただきまして誠にありがとうございます。
ユーザ仮登録が完了しました。

本登録のため、下記のURLへのアクセスをお願いします。
http://ドメイン/users/token/<%= @token %>

参考

ワンタイムURLの生成 – QA@IT