ユーザオブジェクトの管理方法

ここで、このシステムの基本的なアーキテクチャをまとめると次のようになります。

  1. LoginEngineの機能で、認証されたユーザに相当するオブジェクトがセッションに格納される
  2. LoginEngine標準のUserオブジェクトを継承して、それぞれの役割に相当するオブジェクトを生成する
  3. ユーザオブジェクトにビジネスロジックが実装されているのでそれを呼び出して必要な機能を実行する

ですから、問題は、CounselorとClientというクラスのオブジェクトが適切に生成されているかどうかです。これらのクラスはRailsの単一テーブル継承の機能を使って実装されているので、データベース上の行を生成する時にクラスが決まります。つまり、typeというカラムにクラス名が格納されていて、メモリ上にロードする時は、そのクラスによって生成されることになります。

そして、ユーザオブジェクトのデータベース上の生成は次のようにします。

  • カウンセラーは、初期化時にツールで(バッチで)生成する
  • クライアントはLoginEngineの機能によって対話的に生成(登録)する

まず、Counselorは次のようにmigrationのスクリプトの中で生成します。

class InitialSchema < ActiveRecord::Migration
  def self.up
    ...
    Counselor.new do |c|
      c.login = 'co1'
      c.email = 'tnaka@dc4.so-net.ne.jp'
      c.verified = 1
      c.change_password('abcde')
      c.save!
    end
  end
end

カウンセラーは、当面1名で増えたり変更したりすることはめったにないので、これで充分です。もしもの時は、コンソールから対話的にメンテナンスすることになります。

また、カウンセラーのlogin名以外の情報は、一般ユーザと同じようにログインしてから edit の機能で変更できます。

そして、LoginEngineはそのままではsignupの時にUserオブジェクトを生成してしまうので、これを継承してから、Client オブジェクトを生成するように変更します。

$ ruby script/generate conroller Client

ClientControllerは、UserControllerを継承したクラスとして、signupというメソッドを再定義します。修正するのは、 User.new という所を Client.new に書き換えるだけです。

class ClientController < UserController
  def signup
    return if generate_blank
    params[:user].delete('form')
    # @user = User.new(params[:user])
    @user = Client.new(params[:user])
    begin
      ....
    end
  end
end

このコントローラーに対応するビューは、LoginEngineからコピーして日本語化します。

$ cp vendor/plugins/login_engine/app/views/user/* app/views/client

これに合わせて、app/views/test_login/index.rhtmlを次のように修正します。

<h1>こんにちは</h1>

<% if user? %>
<p>こんにちは <%= current_user.lastname %>さん</p>
<p>あなたは<%= current_user.class %>です</p>
<% else %>
<p>こんにちはゲストさん</p>
<% end %>
<ul>
<% unless user? %>
<li><%= link_to 'login', :controller => 'client', :action => 'login' %>
<% end %>
<li><%= link_to "to secret page", :action=>'secret' %>
<% if user? %>
<li><%= link_to 'edit user information', :controller => 'client', :action => 'edit' %>
<% end %>
<li><%= link_to 'logout', :controller => 'client', :action => 'logout' %>
</ul>

そして、データベースを初期化して再実行し、'co1'でログインすると「あなたは Counselor です」と表示されます。サインアップで対話的に作成したユーザでログインすると、「あなたは Client です」と表示されます。

これで、current_user(セッション上のユーザオブジェクト)のクラスによって、対応する処理を行なえばよいことになります。

  • current_user が nil ならばゲストの状態
  • current_user が Client ならば、一般ユーザ(クライアント)がログインしている状態
  • current_user が Counselor ならば、カウンセラー(管理者兼任)がログインしている状態