忍者ブログ
ブログツール、2007/11/06作成
[1] [2] [3] [4] [5] [6] [7] [8
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

属性値に何らかの手を加えてから格納したいときがある。

たとえば、名前関係のフィールドで「フリガナ」フィールドに全角カタカナだけを入力させたい。
正規表現でそれ以外をキックするのはいいけど、
ひらがなや半角カタカナは自動変換できるから自動変換したいと。

方法はいくつかある。
一般的にはフィールド格納をオーバーライドする方法
もう一つはvalidateをオーバーライドしてそこで何とかする方法

今回はまったのは属性代入をオーバーライドする方法。

ActiveRecordを継承したNameクラスにkanaフィールドがあったとする。

普通のRubyクラスなら

class Name
  def kana=(str)
     @kana = NKF.nkf('--katakana', str)
  end
end

しかし、ARの場合@でクラス変数にアクセスできない。
エイリアスで kana=を別名定義して代入させようとするとこれはだめ。
kana=は定義されていなくて、MethodMissingで代入されるからだ。
self.kana=で代入すると普通に無限ループに陥っちゃう。

どうするかというと、別のアクセス方法を試す。

class Name < ActiveRecord::Base
  def kana=(str)
    self[:kana] = NKF.nkf('--katakana', str)
  end
end

とまあこんな感じ。

と考えるとシンボルでアクセスされると自動変換されないか・・・
素直に考えれば、validateをオーバーライドするのがいいのかもね。
どっちにしても検証はしないといけないしね。

class Name < ActiveRecord::Base
  def validate
    self.kana = NKF.nkf('--katakana', self.kana)
     unless self.kana =~ /カタカナかどうかを判別する/
        self.errors.add :kana, "全角カタカナで入力してください"
     end
  end
end

PR
普通にモデルを作っていて、一意性を確保したい属性には、validates_uniqueness_ofでチェックするのがRails流。
スマートにかけていいよね~とか思っていると、ここに落とし穴が。

まず、MySQLをRDBMSに利用している場合のみらしいが、
オプションの :case_sencitive が効かない

大文字小文字を認識してくれないのであるよ。
同じ理由で、ActiveRecord.countもActiveRecord.findも正しくない結果が帰ってくる。

で、ActiveRecord.find/countの時は、:conditionsオプションを指定するときに、
BINARY句を追加する。

こんな感じ
Hoge.find(:conditions=>["BINARY name = ?", "hoge"])

まあ、これはいいとして、validates_uniqueness_ofではどうするか、ということになる。
手っ取り早いが根本的でない解決法は、validates_uniqueness_ofを使わない、という選択肢。
代わりにvalidateメソッドを定義して、
そこでcountを発行して存在するかをチェックする。

このとき、自身がnew_record?かどうかで、自分を除外するコードを足すかどうかを判別する必要がある。

根本的な解決は、ActiveRecord/validate.rbのvalidates_uniqueness_ofをオーバーライドする事になる。
属性の型を認識して、BINARY句を追加するか判別しないといけない。

しかし、更に問題なのはvalidate_uniquness_ofではレコードの一意性が保証されないこと。
いわゆる、トランザクションとかロックの問題なんだけど、これはDBMSに丸投げするのが正解。

マイグレーションを使っているなら最後にユニークインデックスを張ってやる

add_index :tabel_name, :colun_name, :unique=>true

これは、validates_uniqueness_ofを使っている以上はどの場合もそうらしい。

やれやれ。
エラーページを自前のものにしたいとき、これまではごく簡単に、public/500.htmlとかを書き換えてました。

ただ、これだと、imgタグとかを使ったときにRoutingErrorが発生したり、
動的になにかを表示できないと。

で、Render系メソッド呼び出してエラーページをレンダリングしたくなるわけです。

で、ググってみた。
すると、ActionController::Rescue::rescue_actionをオーバーライドするといいよ~
等の情報が。

でも、rescue_actionをオーバーライドすると、
ログなんかも自前で呼び出さないといけなくなるとか。

あ~、結構めんどくさいなあ・・・と思いつつドキュメントとか、ソースを読んでみると、
どうやらrescue_action_in_publicをオーバーライドすればいいらしい。

エラー発生から画面表示までの流れは、

エラー発生->
rescue_action->
エラーハンドラ呼び出し/アクセスもと判別->
(ローカルアクセスの時)rescue_action_locally(開発中のいつものエラー画面)
(パブリックアクセスの時)rescue_action_in_public->
エラーコード取得->エラー画面表示(render :file)

という感じ。

rescue_actionを単純にオーバーライドすると、
・ハンドラ呼び出しがされない
- ロガー呼び出しがない
・アクセスもと判別がない
 - ローカル開発中のエラートラッカーが見られない
等々の問題が。
(もちろん、オーバーライド先で実装すればいい話だけど)

それよりは、もっと末端の
rescue_action_in_publicをオーバーライドすれば、
実際にサービスアクセスされたときだけオリジナルのエラー画面を表示できるし、
ロガー関連もデフォルトのものが自動的に呼び出されるので、
これまでにロガー関係に手を入れていた場合もそのままいける。

ちゅう訳で、
自前エラー画面を実装するときはActionController::Rescue::rescue_action_in_publicをオーバーライドしよう。

ちなみに自分でやったのは、ActionControllerでオーバーライド。

  def rescue_action_in_public(exception)
    code = response_code_for_rescue(exception).to_i
    render_page = 'normal_error'  # 500番台を基本とする
    if code >= 400 && code < 500  # 400番台のエラー
      render_page = 'no_route'
    end
    puts render_page
    puts "xhr request is #{request.xhr?}"
    if request.xhr?
      render :partial=>"#{render_page}"
    else
      render :action=>"#{render_page}", :layout=>'error'
    end
  end

と、こんな感じ。

よく見ると、ドキュメントにも書いてある。

rescue_action_in_public(exception)

Overwrite to implement public exception handling (for requests answering false to local_request?). By default will call render_optional_error_file. Override this method to provide more user friendly error messages.

※Rails1.2系です。2.0系はもっと便利になってるらしい。
え~、まず、前回ベーシック認証でTracを設定したけど、
セキュリティの事を考えてダイジェスト認証に変更。

ダイジェスト認証のパスワードをまず作成。
普通にApacheが入っているので、htdigestコマンドが使える。

# htdigest -c /path/to/.htdigest -c user

とやるとパスワードを聞かれるので、2回入力して完了。
2人目以降のユーザーには[-c]オプションなしでどんどん追記してゆく。

で、Tracdの起動オプションの--base-auth を --authに変更、
.htdigestファイルへのパスと、レルムを指定してやる。

これだけ。

次に、Tracのユーザー権限を変更する。

やり方は、trac-admin /path/to/project add|remove usr permission
という感じで一つ一つ適用してゆく。

デフォルトで、ログインしていないユーザーanonymousと、
ログインしたユーザーauthenticatedが存在していて、
anonymousにチケット発行からソース閲覧までの権限がついている。

基本的に、内輪だけで利用するつもりで、かつ、ソースを見る必要がある人は、
TortoiseSVNで見られるので、Tracではソース表示しない方向で考える。

というわけで、anonymousにはWIKI_VIEW以外の権限を全て削除、
その代わりに全権限を持つパーミッショングループ、
チケット発行とマイルストーン、レポート閲覧まで出来るグループ、
更にWIKIの変更が行えるグループを作成して、
それぞれのユーザーを追加してゆく。

この辺は、Tracのデフォルトで入っているWIKIに詳しいので、
それを参考にする。

次いで、チケット周りのレポートでメールが飛ぶようにする。

この辺の設定は簡単で、
プロジェクトフォルダのconf/trac.iniを編集するだけ。

編集するところは以下の部分
[notification]
admit_domains =
always_notify_owner = false
always_notify_reporter = true
always_notify_updater = true
ignore_domains =
mime_encoding = base64
smtp_always_bcc =
smtp_always_cc = mailaddress_for@admin.com
smtp_default_domain =
smtp_enabled = true
smtp_from = trac@localhost
smtp_from_name =
smtp_password =
smtp_port = 25
smtp_replyto = trac@localhost
smtp_server = localhost
smtp_subject_prefix = __default__
smtp_user =
ticket_subject_template = $prefix #$ticket.id: $summary
use_public_cc = false
use_short_addr = false
use_tls = false

こんな感じ。

これで、チケットに変更がある旅に、mailaddress_for@admin.com宛にメールが届く。
チケット切ってくれた人にも、メールアドレスが登録されていればメールが飛ぶ。

とまあ、こんな感じでひとまずは完了でしょうか。

wikiのページは編集しないとかっこわるいし、
トップのロゴもなにもなしだとあんまりなので、
ぼちぼち埋めていこうかと思ってます。

TortoiseSVNでSubversionのバージョン管理が出来るようになったので、
次はバグトラックと情報共有のためにTracを導入。

まずはYumでTracのインストール。

この辺を参考に、yumのリポジトリを変更。

/etc/yum.repos.d/Dag.repoでやってみたら失敗しちゃったので、
/etc/yum.repos.d/ContOS-Base.repoの最後に以下を追加。

[dag]
name=Dag RPM Repository for Redhat EL4
baseurl=http://apt.sw.be/redhat/el$releasever/en/$basearch/dag
gpgcheck=1
enabled=1gpgkey=http://dag.wieers.com/packages/RPM-GPG-KEY.dag.txt

おお、Redhatのリポジトリがそのまま使えるのね、
と感心しつつyumでtracをインストール。

# yum install trac

どこを見ても、関連するプラグインのインストールではまっているみたいなので、
参考にしているサイトのまねをして一度tracをアンインストール。

# yum remove trac

 で、日本語版をダウンロード。

# wget http://www.i-act.co.jp/project/products/downloads/trac-0.10.4-ja-1.zip
# unzip trac-0.10.4-ja-1.zip
# cd trac-0.10.4-ja-1
# python setup.py install

後は、Pythonがうまくインストールしてくれる。

次に、Tracのプロジェクトを追加。
諸々の設定をある程度共有してプロジェクトを複数立てたいので、
/var/www/trac/以下にプロジェクトを配置することにする。

#trac-admin /var/www/trac/projectname initenv

順次質問されるのでそれぞれにきちんと答える。
Project Name [My Project]>  任意のプロジェクト名を入れる
Database connection string [sqlite:db/trac.db]> そのままエンター
Repository type [svn]> そのままエンター
Path to repository [/path/to/repos]>  svnリポジトリの場所
Templates directory [/usr/share/trac/templates]> そのままエンター
ここで、tracdを起動して、きちんと動くのを確認。

# tracd -p 8000 /var/www/trac/projectname

これで、対象サーバーにアクセスしてみて動作を確認してみる。

http://localhost:8000/projectname

きちんと動いてる。

ここまでは順調。

アクセス制限をベーシック認証で行うために、htpasswdファイルを作る。

# htpasswd -c /var/www/trac/.htpasswd [アカウント名]
パスワードを聞かれるので、任意のパスワードを設定。
Linuxユーザーのパスワードとは無関係なので注意。

二人目以降のパスワードは-cオプションを外して同じ事を繰り返す。

ベーシック認証のためにApacheと連携させてみる。
が、ここではまった。

mod_pythonなど、諸々のプラグインをインストール、
Apahceの設定のために/etc/httpd/conf.d/trac.confを作って設定。
先ほどのTracプロジェクトフォルダのオーナーをapacheユーザーに変更。

Apacheを再起動してアクセスしてみる。
http://localhost/trac/projectname

プロジェクトページはきちんと表示されるし、
ログインもきちんと出来る。

でも、画面の上の方にSubversionへのアクセス制限が無い、とエラー表示。
どうやら、Tracプロジェクトで指定したSubversionリポジトリのformフォルダへのアクセス権が無い、
といっているらしい。

調べてみると、そのフォルダの読み書き権限をapacheユーザーに与えてやればいいらしいが、
プロジェクトが増えるたびにその操作をするのも大変だし、
第一セキュリティ的に問題がありすぎ。

で、他の方法を探す。

ちとしらべてみると、Subversionの旧バージョンに発生するバグらしい。
インストールされているSubversionはCentOSで自動的にインストールされたものなので、
アップデートしてみる。

# yum update subversion

最新版になったところで再トライ。

すると、今度は違うエラーが。
「Unsupported version control system "svn"」とか何とか・・・

調べると、Python系のプラグインのバージョンが何とか・・
いろいろと情報が錯綜していて、Python門外漢の自分には何の事やらさっぱり、
と頭をかかえる。 

で、ハタと思った。

tracdでなにが悪いの?と。

というわけで、構成をシンプルに考え直す。
1.宅内ルータからのポートフォワーディングでしか外からアクセスできない。
2.ポートフォワーディングで80番を開放しているwebサーバーがすでにある。
3.外からアクセスは結局、そのサーバーからリバースプロクシでtracサーバーに転送するつもりだった。
4.別にhttpsでアクセスさせるつもりはない。

と考えれば、Apacheを使うメリットが思いつかない。

ベーシック認証がtracdで使えるらしいので、
オプションを調べる。

# tracd --help

おー。きちんとベーシック認証に対応してるではありませんか。
デーモナイズも出来る。
ただ、停止のためのオプションはないので、
オプションでpidを書き出させて、それを使ってプロセスをkillしないといけない。

tracのヘルプを見ると、複数プロジェクトもこれでうまくいけるらしい。

というわけで、起動、停止用のシェルスクリプトを書いて、
/etc/init.dにコピー、chkconfigで起動リストに加えて完了。

試しにサーバーを再起動してみて、きちんとTracdが動いているのを確認。

お~、うまくいった。

後は、プロジェクト毎の権限設定などをしてゆく。

というわけで続く・・・・

前のページ      次のページ
ついめ~じ
ブログ内検索
フリーエリア
サニーカメラ
Powered by Ninja Blog    template by Temp* factory    icon by MiniaureType

忍者ブログ [PR]