OpenID 開発ログ。
すでにローカルユーザーテーブルを持っている場合にどうOpenID対応するか。
まず、スキーマ変更。
class AddOpenIdSupportForWjUsers < ActiveRecord::Migration def self.up # add type add_column :wj_users, :type, :string, :limit => 64, :null => false, :default => "WjLocalUser" # add open_id column add_column :wj_users, :open_id_uri, :string, :limit => 255, :null => true, :default => nil # change :login_password_hash, :email change nullable. change_column :wj_users, :login_password_hash, :string, :limit => 32, :null => true, :default => nil change_column :wj_users, :email, :string, :null => true, :default => nil end
type列重要。OpenID ユーザーと、LocalUser は、ポリモーフィズムで解決します。単一テーブル継承戦略で。
そのため、パスワードとメールアドレスの列はnull値を可能に。
次に、クラスを作成。
$ ruby script/generate model WjLocalUser $ ruby script/generate model WjOpenIdUser
でいずれも、元々持っているユーザークラスを継承する。
# app/models/wj_local_user.rb class WjLocalUser < WjUser; end; # app/models/wj_open_id_user.rb class WjOpenIdUser < WjUser; end;
であとは、パスワード や メールアドレス列 に関連するメソッドを既定のクラスから、継承した子クラスに移動。
# app/models/wj_user.rb class WjUser < ActiveRecord::Base - def self.authenticate(name, password) - user = self.find_by_login_name(name) # app/models/wj_user.rb class WjLocalUser < WjUser + def self.authenticate(name, password) + user = self.find_by_login_name(name)
最後にユーザー作成している部分(おそらくコントローラーコード)をUser.new => LocalUser.new とするか OpenIdUser.new とするか決めていけば完了です。Select する部分に関しては基底クラスのfind_* メソッドでOK(レコードがオブジェクト化されるときに、type列をみてActiveRecordが自動的にクラスを判断)。
これでモデルクラスはほぼOKで。