cookieで前回アクセス時の情報を復元

クッキーの値をDBに格納しておき、
次回同じユーザがアクセスしたときに格納しておいた情報を参照できるようにするするためのベースの仕組みの試作を行ってみました。

テーブル定義

まず,cookieを保存しておくテーブルは以下のように定義します。

class CreateVisitors < ActiveRecord::Migration
  def self.up
    create_table :visitors do |t|
      t.column :value, :string, :limit => 32, :null => false
      t.column :hashed, :string, :limit => 32, :null => false
      t.column :expired, :date, :null => false
      t.timestamps
    end
  end

  def self.down
    drop_table :visitors
  end
end

カラムとして以下のものを定義しています。

cookieの値
上記の値と現在日時を元にMD5でハッシュ化した値を入れておくカラム、この値もcookieとしてクライアントに格納して、cookieの値の送信者が正当であるかを照合する。
cookieの有効期限

モデル

以下のようにcookieのモデルを定義。cookieの取得、生成を行うfind_from_cookieメソッドを定義しました。

class Visitor < ActiveRecord::Base
# サイト訪問者のcookieを記録するモデル
# +value+(クッキーの値), +hashed+(照合用のハッシュ値のクッキー値), +expire+を含むモデル
  attr_accessor :must_send

  public
  # cookie情報をもとに行を検索
  # 未作成または、期限まで1ヶ月以内であれば新規生成
  # 有効期限が近ければ更新
  def self.find_from_cookies(cookies)
    visitor = if cookies[:visitor] then
      value = cookies[:visitor]
      Visitor.find_by_value(value)
    else
      nil
    end
    new_visitor = if !visitor or visitor.hashed !=  cookies[:visitor_md] then  
      # 新規(未作成 or ハッシュとの不一致)
      Visitor.new
    elsif visitor.expired < Date.today + 30 then 
      # 更新(30日以内に有効期限切れ)
      visitor
    else
      # 変更不要
      nil
    end
    if new_visitor 
      value = create_cookie_value
      new_visitor.value = value
      new_visitor.hashed = Digest::MD5.hexdigest(value+Time::now.strftime("%Y%m%d%H$M$s"))
      new_visitor.expired = 3.month.from_now
      new_visitor.must_send = true
      new_visitor.save
      new_visitor
    else
      visitor.must_send = false
      visitor
    end
  end
  
  private
  
  # クッキーの値を生成
  def self.create_cookie_value()
    ActiveSupport::SecureRandom.hex(16)

  end
end
cookieの有効期限が近いか、cookieがなければcookieを新規作成します。
cookieはランダム値のcookieとそのランダム値と日時を結合してMD5ハッシュ化したものを生成してDBへの保存します。クライアントからの送信時、その2つのcookie値を照合して正当性を判断します。

controller

コントローラーでは、モデルのfind_from_cookieメソッドで得たcookieのモデルを取得、(必要であれば)クライアントへそのcookie値を送信するメソッドを定義。before_filterでそれを実行するようにしました。

class Customer::BaseController < ApplicationController
  
  
    before_filter  :set_visitor_cookie
    attr_reader :visitor

    def initialize
    end

    protected
    
    # Visitorのcookie生成
    # 未作成または、期限まで1ヶ月以内であれば新規cookieを生成
    def set_visitor_cookie()
      visitor = Visitor.find_from_cookies(cookies)
      if visitor.must_send :
        cookies[:visitor] =
          {:value => visitor.value,
            :expires => visitor.expired
          }
        cookies[:visitor_md] =
          {:value => visitor.hashed,
            :expires => visitor.expired
          }
      end
      @visitor = visitor
    end
    
   
end

ここで取得したcookieのモデル(visitorモデル)のidを他のテーブルから参照して、前回アクセス時の情報を復元するというような使いかたになるのかな?

次は?

このかたちじゃ、使いにくいので、Plugin化することを考えるかな?