[Rails]acts_as_authenticatedを使う
ログイン、認証周りの処理を作成するのに使えるかと思い調べてみた。
インストール
インストール等については、以下を参照した。
プラグインインストール後、認証に対応したモデルとコントローラを生成する。
$ ruby script/generate authenticated MODEL CONTROLLER
概要
上記手順を実行すると、以下のファイルが生成される。
- app/models/user.rb
- app/controllers/account_controller.rb
- app/views/account/index.rhtml
- app/views/account/login.rhtml
- app/views/account/signup.rhtml
- lib/authenticated_system.rb
できそうなことは、大体以下のような感じ。
- サインアップフォームによるユーザ登録
- ログイン処理
- ログアウト処理
- 非ログイン時のアクション実行禁止
カスタマイズ
とりあえず今回はサインアップの機能は入らないのでごっそり削除したのと、自前で用意したホーム画面を表示したいので、Controllerのあたりをゴリゴリ書き換えた。
また、自前のホーム画面を表示するためにhomeアクションを追加している。いろいろ弄った結果、こんな形になった。
class AccountController < ApplicationController # Be sure to include AuthenticationSystem in Application Controller instead include AuthenticatedSystem # If you want "remember me" functionality, add this before_filter to Application Controller before_filter :login_from_cookie # say something nice, you goof! something sweet. def index if logged_in? then redirect_to(:action => 'home') else redirect_to(:action => 'login') end end def login redirect_to :action => 'home' if logged_in? return unless request.post? self.current_user = User.authenticate(params[:login], params[:password]) if logged_in? if params[:remember_me] == "1" self.current_user.remember_me cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at } end flash[:notice] = "Logged in successfully" redirect_to :action => 'home' end end def home if logged_in? then @members = current_user.members else redirect_to :action => 'login' unless logged_in? end end def logout self.current_user.forget_me if logged_in? cookies.delete :auth_token reset_session flash[:notice] = "You have been logged out." redirect_to :action => 'login' end end
非ログイン時のアクション実行禁止
Controller内に以下の記述をするだけ。非ログイン時にはaccountコントローラのloginアクションが実行されるみたい。
include AuthenticatedSystem before_filter :login_required
ここら辺の動きの詳細は authenticated_system.rb 内の login_required -> access_denied メソッドを読めばわかる。
[日記]mixiリニューアル記念
と、いうわけではないが(2日も遅れてるし)、mixiの日記を外部ブログ、こちらに設定してみました。技術ネタがほとんどになってしまうが、先に書いたとおり規則正しい生活をしようと思うところもあり、これからちょくちょく日記的なことも書いていこうと思います。
よろしくお願いします。
[trac]tracのRuntimeError
自宅サーバに導入しているtrac環境のリポジトリにアクセスすると、ときどき以下のような変なエラーを出す。
RuntimeError: instance.__dict__ not accessible in restricted mode
Subversionへのアクセスは問題無くできるので放置していたのだが、やはり気持ち悪いのでちょっと原因を調べてみようと思った。
と、思っていたら、以下のページにそのものずばりの解決策が公開されていた。
10分で解決。いや〜とりあえずググってみるもんだなぁ。
(追記:01:56) たった今エラーが再発してしまいました。対処前に比べるとかなり発生頻度が減ったようですが、後日調べることにしてみます...
(追記:9/25) 上記リンク解説中、「各サイトごとの」という記述を意識していませんでした。VirtualHost を2つ持っているので、追加し忘れたもう一方のファイルへも設定を追加しました。
[Rails]redMineのインストール
最近、Railsベースのプロジェクト管理ソフトとして話題になっているredMineをインストールしてみた。
以下、自宅の環境(Vine Linux)にインストールした履歴。
Ruby on Railsを使えるようにする
Ruby環境の整備
Railsベースなので、まずはRubyが動作する環境にする必要がある。
基本方針として、Vineのパッケージとして提供されているものについてはそちらを利用することにするので、以下のパッケージをインストールした。
irb 1.8.5-0v11.1 rbbr 0.5.1-0v11 rdoc 1.8.5-0v11.1 refe 0.8.0-0v11 ruby 1.8.5-0v11.1 ruby-devel 1.8.5-0v11.1 ruby-xmlparser 0.6.8-0v12
Ruby Gemsのインストール
RailsはRubyにおけるパッケージマネージャであるGemsを使用してインストールするのが一般的なため、まずはGemsをインストールする。
1. 以下のURLからrubygems-0.9.2.tgzを入手
http://docs.rubygems.org
2. ソース解凍、インストール
# tar xvfz rubygems-0.9.2.tgz # cd rubygems-0.9.2 # ruby setup.rb config # ruby setup.rb setup # ruby setup.rb install
PostgreSQLアダプタ
今回データベースとしてPostgreSQLを使用するので、アダプタをインストールする。
# gem install postgres -- --with-pgsql-lib-dir=/usr/lib/postgresql --with-pgsql-include-dir=/usr/include/pgsql
redMine本体のインストール
redMine入手と解凍
# wget http://rubyforge.org/frs/download.php/22783/redmine-0.5.1.tar.gz 〜 # tar xvf redmine-0.5.1.tar.gz
DB環境の作成
Postgres上にredMineが使用するDBユーザを作成。今回は以下の形で作成した。
表領域 : redmine_space データベース : redmine_db ユーザ : redmine パスワード : redmine
次に、redMineが上記DBに接続できるようにする。解凍ディレクトリ下のconfig/database.yml.sample を database.yml にコピーし、以下のように書き換える。
adapter: postgresql database: redmine_db username: redmine password: redmine
シェルプロンプトから以下のコマンドを実行し、テーブルの作成とデフォルトデータをロードする。途中、言語を聞かれるのでjaを選択。
# rake db:migrate RAILS_ENV=production # rake load_default_data RAILS_ENV=production
上記準備ができれば、ruby script/server でredMineが起動する。
ブラウザから http://localhost:3000 にアクセスして動作確認。
某牛丼屋のキャンペーンで
「三杯めは100円!」などといっているが、「三杯も食えるか!」と思ったのは私だけ?
別にいっぺんに食べなくてもいいみたいでした。
だって松井がCMやってるからさぁ、普通に食べそうだもんあそこらへんの人は...
ORA-08177: このトランザクションのアクセスをシリアル化できません
Oracleでトランザクション遮断レベルをSERIALIZABLEに設定すると、こんなエラーが発生することがある。今回、お客さまがマスタに1レコード追加したとたんに頻発するようになったらしい。
マニュアルによると、「このエラーが発生することを前提として」例外を捕捉しリトライするようなプログラムを書かなければいけないらしいけど、作ったの4年も前だしそんな知識なかったから、いたるところでSERIALIZABLE設定をしている。
今更そんな多くの箇所に手を入れるのも嫌だし、直近の対応として例外が発生しなくなるようにしなければいけないため、いろいろと情報を探っていたら、どうも次のような現象らしい。
Oracleは、データの記録を「データブロック」という単位で行っているが、あるレコードをどのデータブロックに割り当てるかはOracleの内部で処理されており、同じテーブルのデータだからといって同じデータブロックに割り当てられるとは限らない。逆に、全く違うテーブルのデータが同じデータブロックに割り当てられる可能性もある。
今回発生したエラーは、複数のスレッドがたまたま同時に同じデータブロックにアクセスしようとしたとき、シリアル性を保証できないために発生する例外のようだ。
Oracleのデータは、削除や追加するたびに違うデータブロックに割り当てられるので、対象データをいったん削除し、再度追加することで異なるデータブロックに再割り当てされ、競合は発生しなくなるのではないか?
ということで、お客さまにその旨連絡して、様子を見てもらうことにした。
結果がわかるのは明日以降だろうけど、これで解決できるのであればラッキー。
(追記 9/25) 本日お客様から呼び出されちゃいました orz... やはり上記手順は暫定対処でしかないので、本質的にはソース改修するしかないようです。