とりあえず新規アプリケーションを作ってユーザ認証とかが動くまで

  • 2008-09-13 ちょっと修正。sqlite3-ruby も必要っぽかった。

仕事ではRails 1.2.6しか触ってないし既にテンプレありの状態からだったので、最新のRails 2.1.1で新規アプリをどう作るか確かめるの巻。
環境は Mac OS 10.4 だけどRubyが動けばどこでも問題ないと思われる。とりあえずMacPortsは入ってるという前提。

Railsのインストールまで

Ruby, RubyGems, Git を MacPorts で入れて、Rails, Mongrel, sqlite3-ruby を gem で入れる。
Windowsなら、RubyActiveScriptRuby、Gitはmsysgit(インストール時に「コマンドプロンプトで使う」みたいなオプションを選ぶ)を入れれば、コマンドプロンプトでほぼ同じように作業できるはず。

$ sudo port install ruby
$ sudo port install rb-rubygems
$ sudo port install git-core
$ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-darwin8]
$ gem -v
1.2.0
$ git --version
git version 1.6.0.1
$ sudo gem install rails
$ sudo gem install mongrel
$ sudo gem install sqlite3-ruby
$ rails -v
2.1.1

アプリケーションの生成、Restful Authentication プラグインのインストール

$ rails example
$ # (いろいろ表示...)

$ # とりあえずDB初期化(適当アプリだしSQLite3をそのまま使う)
$ cd example
$ rake db:create

$ # Restful Authentication プラグインを入れる
$ # 規約に従った名前に変更する必要がある
$ script/plugin install git://github.com/technoweenie/restful-authentication.git
$ mv vendor/plugins/restful-authentication vendor/plugins/restful_authentication

Restful Authentication で認証機構を作成

ユーザモデルやroutes, ヘルパーなどいろいろ初期設定。メールによるアクティベーションつきで設定する。
aasm はステートマシン用ライブラリ?で acts_as_state_machine より新しいらしい。

$ script/generate authenticated user sessions \
  --include-activation \
  --aasm

今の状態だと「uninitialized constant Authorization::AasmRoles::AASM」と言われて migrate もできない。上を実行すると表示されるように、以下の追加作業が必要。
まず、aasm の gem を入れる。GitHub にあるので GitHub を gem の取得先に追加。

$ sudo gem sources -a http://gems.github.com
$ sudo gem install rubyist-aasm

config/environments.rb に以下を追加してインストールした gem を使うよう設定。

  # config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
  # config.gem "aws-s3", :lib => "aws/s3"
  gem "rubyist-aasm", :lib => "aasm"  # 追加

この後 migrate。usersテーブルとかが追加される。

$ rake db:migrate

あと、config/routes.rb に以下が足りないようなので追加(map.resources :users のところは変更)。
2行目の意味はまだよく理解してませんが。

map.activate '/activate/:activation_code', :controller => 'users', :action => 'activate', :activation_code => nil
map.resources :users, :member => { :suspend => :put, :unsuspend => :put, :purge => :delete }

さらに、認証メールの送信先を設定。面倒なので、メールは送ったことにして済ませるだけにする。config/environments/development.rb に以下を追加。

config.action_mailer.delivery_method = :test

これで、メールは実際には送信されず、ログにメール内容がデバッグ出力されるだけになる。

ユーザ登録してみる

これで、ユーザ登録の準備ができたので登録してみる。サーバを起動して、

$ script/server

http://localhost:3000/signup にアクセスするとユーザ登録画面が出る。メールアドレスは、どうせ送られないので hoge@example.com とか適当。
登録すると、script/server の出力に

Visit this url to activate your account:

  http://YOURSITE/activate/9d5c87f84c0d9907a9c863759edd5f59bf0e20bd

みたいに認証用URLが出ているので、YOURSITEの部分を localhost:3000 にしてブラウザにコピペすると、ユーザ登録が完了する。
ログには UPDATE users .... state = 'active' のような、ユーザを有効にするようなSQLがでているはず。

アクセス制御の確認

これだけだと認証とかがちゃんと動いてるのかなんだかよくわからないので、原始的なブログをつくってみる。
まず、ブログエントリのモデル Entry の足場を作成。エントリは誰かユーザーを投稿者として持つとする。

$ script/generate scaffold entry title:string content:text user:references

Entry モデルとか EntriesController とかビューとかが作られる。できたら、migrate。

$ rake db:migrate

User と Entry の関連づけも行う。ついでに attr_accessible も。

class User < ActiveRecord::Base
  has_many :entries  # 追加
class Entry < ActiveRecord::Base
  belongs_to :user  # 追加
  attr_accessible :title, :content # 追加

これで手抜きブログシステムは完成したので、あとはアクセス制御を追加する。

まず、UsersController にある

include AuthenticatedSystem

を、ApplicationController に移す。これで Restful Authentication プラグインが提供する便利メソッドがさっき作成した EntriesController からも使えるようになるので、EntriesController に以下の修正を加える。

class EntriesController < ApplicationController
  # /entries と /entries/show/:id 以外にアクセスされるとログインを要求する
  before_filter :login_required, :except => [:index, :show] # 追加

#(中略)
  def create
    @entry = Entry.new(params[:entry])
    # ログインユーザを Entry モデルの user にセットする
    @entry.user = current_user  # 追加

これで準備完了。

認証機構を試す

試す前にさっきのセッションが残っているかもしれないので http://localhost:3000/logout にアクセスしてログアウトしておく。

その後、ブラウザで http://localhost:3000/entries/ にアクセスすると「Listing Entries」という空の一覧表示画面が表示される。さっき :except で :index を除外しておいたのでログインは要求されなかった。OK。

で、ここに「New Entry」というリンクがあるのでクリックすると、はじめてログインを要求される。このリンクは :new アクションなので :login_required に引っかかるのが正しい。OK。

さっき登録しておいたユーザでログインすると、タイトルと本文とUserが入力できるブログエントリ投稿画面が現れる。Userは無視してタイトルと本文を入れ、Createボタンを押すとエントリが作成される。script/server の出力に INSERT INTO entries ... というSQLが出力されているはずなので、その user_id にログインユーザの id が入っていればログインユーザを投稿者としてセットする処理も問題ない。OK。
/entries/ の一覧表示に戻ると、User列には # とか出ますがまあ手抜きだししょうがない。

とりあえず最低限のアプリケーションの骨格はできたので、流行ってるぽい(独断とGoogle先生の託宣から)プラグインとかを突っ込んでいこうと思う。