8/03/2009

状態遷移機械を使ってARを制御(Rails2.3.2 + aasm)

目的:状態遷移機械機能を使って、RailsのARを制御する。



気をつけること。状態遷移機械機能は、ActiveRecordに対するモジュールの形で提供され、gemとして各ウェブアプリにインストールする。acts_as_state_machine(obsolete)とaasmの2つがあるが、前者は更新が止まっており、後者がよくつかわれているらしい。最新のrestful_authenticationプラグインでも、後者のaasmを推奨している


  1. gemインストール。

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


  2. railsアプリにインクルードするには、config/environment.rbに次の記述が必要。

    config.gem "rubyist-aasm", :source => "http://gems.github.com", :lib => 'aasm'

    config.gemを入れておくと、他のホストに配備した時に`rake gem:install'でライブラリがインストールできる。
  3. aasmで状態管理をするモデルSampleを作る。Sampleの各オブジェクトに状態がつく。

    ./script/generate model Sample content:text state:string
    rake db:migrate

    stateという名の文字列型のカラムは、Sampleモデルで生成されたオブジェクトが持つ「状態」を格納しておくレジスタ。この状態保持レジスタは、モデルに入れておかないとaasmが動作しない。

  4. app/models/sample.rbを編集。

    class Sample < ActiveRecord::Base
    include AASM

    aasm_column :state
    aasm_initial_state :q

    aasm_state :q
    aasm_state :editing, :enter => :open_gui, :exit => :close_gui
    aasm_state :executing, :enter => :open_browser, :exit => :close_browser
    aasm_state :quit

    aasm_event(:go_exec, :success => :show_status)do
    transitions(:from => [:q, :editing],
    :to => :executing,
    :on_transition => :going_execution)
    end

    aasm_event(:go_edit,:success => :show_status)do
    transitions(:from => [:q, :executing],
    :to => :editing,
    :on_transition => :going_edition)
    end

    aasm_event(:quit_session, :success => :show_status)do
    transitions(:from => [:edititng, :executing],
    :to => :quit,
    :on_transition => :end_session)
    end

    def show_status
    puts "I'm in #{self.aasm_current_state}"
    end

    def open_gui
    puts 'GUI Editor opened.'
    end

    def close_gui
    puts 'GUI Edior closed.'
    end

    def open_browser
    puts 'Browser opened.'
    end

    def close_browser
    puts 'Browser closed.'
    end

    def going_execution
    puts "Now we're entering execution."
    end

    def going_edition
    puts "Now we're entering edition."
    end

    def end_session
    puts "Session end."
    end

    end

    いくつか


    • aasm_columnは状態を入れておくレジスタとして使うモデルのカラムをシンボルで指定。


    • 初期状態はaasm_initial_stateで指定するが、状態を宣言するaasm_stateでも初期状態を指定しておくこと。


    • メソッドが駆動するタイミングは、:exit, :on_transition, :enter, :successの順に決まる。


    • 「Obj.状態名?」で、それが今の状態かどうかが判断できる。状態遷移は「Obj.イベント名!」で起る。



12/04/2007

activescaffold + acts_as_authenticated レシピ

activescaffold + acts_as_authenticated レシピ


$ rails qplan
$ cd qplan
$ ./script/plugin install http://activescaffold.googlecode.com/svn/tags/active_scaffold
$ ./script/plugin install acts_as_authenticated

そのほか日本語対応のための設定やデータベースの設定が必要。sqlite3を使うにはdatabase.ymlで

adapter: sqlite3
database: db/development.sqlite3


○acts_as_authenticatedのための準備


$ ./script/generate authenticated user(モデル名) #{account}(コントローラ名)

認証用のテーブル(モデル)を作るためのマイグレーションファイルがdb/migrateに作られる。

$ rake db:migrate

./app/controller/#{account}_controller.rbにある以下のメソッド達をapplication.rbにコピー



include AutheticationSystem # 必ず入れよ

def index
redirect_to(:action => 'signup') unless logged_in? || User.count > 0
end

def login
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
redirect_back_or_default(:controller => '/mroadmap', :action => 'index')
flash[:notice] = "Logged in successfully"
end
end

def signup
@user = User.new(params[:user])
return unless request.post?
@user.save!
self.current_user = @user
redirect_back_or_default(:controller => '/mroadmap', :action => 'index')
flash[:notice] = "Thanks for signing up!"
rescue ActiveRecord::RecordInvalid
render :action => 'signup'
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_back_or_default(:controller => '/mroadmap', :action => 'index')
end



認証が必要なコントローラには、./app/controllers/#{controller}_controller.rbに次の1行を挿入。

class #{なんちゃら}Controller < ApplicationController
before_filter :login_required

○activescaffoldのための準備

$ ./script/generate migrate CreateTables
./db/migration/0XX_create_tables.ymlを編集 (Mytableというモデルを作ったとする)
$ rake db:migrate
$ ./script/generate model --skip-migrate Mytable
$ ./script/generate controller mytable
./app/controller
./app/views/layouts/mylayouts.rhtmlを以下のように編集して保存。




<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>My Application</title>
<%= javascript_include_tag :defaults %>
<%= active_scaffold_includes %>
</head>
<body>
<%= yield %>
</body>
</html>


./app/controller/#{controller}_controller.rbに次の宣言

class #{なんちゃら}Controller < ApplicationController
before_filter :login_required # 認証の利用宣言

active_scaffold :mytable do |config|
# ここに設定をいれる
end
layout "mylayout" #./app/views/layouts/mylayout.rhtmlのこと
end


○HABTMを使うとき。

たとえば2つのテーブルtableaとtablebがあったら./db/migrate/0xx_*ファイルを次のようにしてみる。



def self.up
create_table "tablea" do |t|
t.column "noa", :integer
t.column "plana", :text
t.column "created_at", :date
t.column "updated_at", :date
end

create_table "tableb" do |t|
t.column "nob", :integer
t.column "year", :integer
t.column "planb", :text
t.column "created_at", :date
t.column "updated_at", :date
end

create_table "tableas_tablebs", :id => false do |t|
t.column "tablea_id", :integer, :default => 0, :null => false
t.column "tableb_id", :integer, :default => 0, :null => false
end

end



さらにモデルtablea,tablebで次のような宣言をしておく。対称なのでaとbを入れ替えよ。



has_and_belongs_to_many :tableas
def to_label
"#{noa}"
end



noaはcolumnの名前だ。

○GetTextを『使わない』日本語化
次のファイルを./lib/japanize.rbとして保存し、./config/environment.rbの最後に次の1行を追加。

require "japanize"


./lib/japanize.rb



class Object
AS_JP_MAP = {
"Replace With New" => "新しい値に置換",
"Edit" => "編集",
"Show" => "表示",
"Update" => "更新",
"Delete" => "削除",
"Search" => "検索",
"Create New" => "新規作成",
"Reset" => "リセット",
"hide" => "隠蔽",
"show" => "表示",
"Cancel" => "キャンセル",
"Found" => "件見つかりました。",
"Create" => "作成",
"Close" => "閉じる",
"No Entries" => "データがありません",
"Live Search" => "リアルタイム検索",
"Search Terms" => "検索ワード",
"Create %s" => "%sの新規作成",
'Create Another' => "新規追加",
'Add From Existing'=> "を追加",
'- select -' => "-- 選択 --",
'Remove' => "除外",
'Previous' => "前",
'Next' => "次",
'%s for %s' => "%2$s の %1$s (%1$s for %2$s)",
'Update %s' => "%sの編集",
'Are you sure?' => "本当によろしいですか?",
'Request Failed (code 500, Internal Error)' => "エラーが発生しました。",
'Created %s' => "%s を作成しました。",
'Deleted %s' => "%s を削除しました。",
'Updated %s' => "%s を更新しました。",
"Version inconsistency - this record has been modified since you started editing it." => "更新が衝突しました。",
'Show %s' => "%s の表示",
"no options" => "選択肢がありません。"
}
alias_method :as__without_jp, :as_
def as__with_jp(*args)
pars = args.dup
fmt = pars.shift
text = AS_JP_MAP[fmt]
if text
text = text % pars unless pars.empty?
return text
end
return as__without_jp(*args)
end
alias_method :as_, :as__with_jp
end


11/26/2007

activescaffold : rails レシピ

Active ScaffoldはAJAXなインターフェースを提供してくれるrailsのプラグインです。やりかた。

  1. rails phonebook
  2. cd phonebook
  3. ./script/plugin install http://activescaffold.googlecode.com/svn/tags/active_scaffold
  4. ./script/generate model Address # モデルを作る。migrationの作成ファイル./db/migration/001_create_adddres.rbができるが、無視しておく。
  5. ./script/generate controller address # コントローラーを作る
  6. ./app/controller/address_controller.rbを開いて次の2行を挿入。
    active_scaffold :address
    layout "address_layout"
  7. ./app/views/layouts/address_layout.rhtmlを作成して次のようなrHTMLコードを挿入。


    <%= javascript_include_tag :defaults %>
    <%= active_scaffold_includes %>

  8. ./script/server
  9. scaffoldのあり方が根本的に変わるかも。
    http://wota.jp/ac/?date=20071110#p01
    が参考になります。

9/20/2007

railsでgettext+gettext_scaffoldを使って早く日本語対応WebDBを作る方法 - その2

gettext_scaffoldは日本語のラベル表記を管理するのに便利だが,どうもうまく動作しなかった。:action => :list で指定されているリンクで表示にエラーがでまくる。関連資料を探すとこちらにgettext_scaffoldの怪しいところを修正したパッチがあったので適用してみた。


cd vender/plugin/gettext_scaffold
patch -p 0 < gettext_scaffold_39.patch


オプション-p 0を付けないとパッチが適用されなかったが。それでも適用は未完であった。SVNのheadと修正分の差分とのことだったが,SVNのheadといっているソースが違うのか?

とにかく、無理矢理パッチしてgenerator/gettext_scaffold/template以下のファイルを少し修正しなければならない。このフォルダにあるrhtmlファイルでrender 'show'となっているところを render 'form'と書き換える。どうやらパーシャルの指定が不十分のようだ。とりあえず、デフォルトで使われている_form.rhtmlを使えばエラーは出ない。ここまでの作業を ./script/plugin install svn://.../gettext_scaffoldの後に行って,次の作業をおこなう。


  • rake gettext:setup
  • ./script/generate model テーブル名
  • migrateファイルを編集してテーブル定義
  • rake db:migerate
  • ./script/generate gettext_scaffold テーブル名
  • rake gettext:update_po
  • poファイルを編集
  • rake gettext:make_mo


テーブルが既に定義されている場合は generate gettext_scaffoldから行ってもよい。ふー

8/20/2007

railsでgettext+gettext_scaffoldを使って早く日本語対応WebDBを作る方法

↑そういうことで備忘録。
  1. rails proj ; cd proj # railsでプロジェクト作成。
  2. mysql ; create database proj # MySQLサーバにデータベースを登録。
  3. ./script/plugin install svn:/rubyforge.org/var/svn/gettextscaffold/gettext_scaffold # プラグインインストール
  4. rake gettext:setup # GetTextの準備
  5. ./config/enviroment.rbの最後に次の2行をいれる。
    require 'gettext/rails'

    GetText.locale ='ja'
  6. さらに、./app/controller/application.rbに次の1行をいれる。
    init_gettext 'プロジェクト名'

  7. ./script/generate model Table # モデルを作成
  8. ./db/migrate/001_create_tables.rb を編集してやる
  9. rake db.migrate # MySQLにテーブルを作成
  10. ./script/generate gettext_scaffold Table # GetText雛型を作成
  11. rake gettext:update_po
  12. ./po/ja/Table.poを編集。日本語ラベルを定義
  13. rake gettext:make_mo
おおよその流れはこうです。

8/10/2007

Ubuntu 7.04 FeistyでのRails - つづき

家で仕事はしないつもりだったが、自宅のノートPCにもRails+GetText環境を入れておこうと思っていると、またまたはまってしまった。折角の週末の夜に仕事をするものだから、新婚の妻はふて寝してしまった。

今日見つけた方法、つまりgem,rails以下aptを使わない直接叩き込む方法でインストールしていると、最後のgettextでたくさんエラーが出てきた。mswin用のgettextなら入るが、rake gettext:***でうまくいかない(あたりまえか)。ruby-gettextインストール時のエラーを見ると、stdio.hが無い!とか言われている。




えー!標準ヘッダがないの〜?

updatedbしてlocate stdio.hでも見当たらない・・・・・

'ubuntu stdio.h'でぐぐったら、やっぱり・・・・orz

ubuntuはデフォルトでちゃんとC開発環境がインストールされないこともあるそうだ。debパッケージ build-essentialをインストールする。無事ruby-gettextがインストールされる。

Ubuntu 7.04 FeistyでのRails

Ubuntu 7.04 FeistyでパッケージマネージャでインストールしたRailsでのトラブル記録。

  1. gettext_scaffoldを導入し国際化したWebアプリケーションは、scaffoldが吐いたコントローラのメソッドcreateで"stack level too deep "といって、どうやら無限ループに行ってしまうようだ。
  2. つらつら情報を探しているうち こういう 情報を入手。
  3. どうも、libgettext-ruby-1.8パッケージのバージョンが良くないようだ、アップデートしようと思ったがない。こまった。
  4. いっそ、gemを叩いて直接gettext-rubyをインストールしよう。そう思い立ってgettext-ruby-1.10.1をインストールしてみる。1で起こったようなループが起こらず処理が帰ってきている。よかた。
  5. ところが、poファイルを更新する等してrake gettext:make_moなどをおこなうと "gettext/utils"がありませんよといわれる。どうやらrakeが見ているディレクトリがうまく設定されていないようだ。
  6. しかたないので、ubuntuパッケージで提供されてるrails, rubygems(え?これも!!)のパッケージを削除し、直接インストールする。
  7. gemでrails、gettextをインストールすると件のWebアプリケーションは正常に動いた。
パッケージマネージャでruby関係をインストールするとgem周りで不具合(ディレクトリ構成の違い)があるらしい。
ちなみにubuntu提供のrailsで作ったWebアプリは/usr/shareあたりにシンボリックリンクを張るので、ソースをtarでかためてもっていくなど、可搬性がない。railsはパッケージでなく、gemでインストールというのは鉄則のようだ。

10/20/2006

タグはAND検索がよいのか、OR検索がよいのか

リンクをdeliciousに移行して思った。

個々のリンクをタグ付けしたのだが、2つ以上のタグはAnd的なのかOr的なのか。

タグ付けたれたリンク群でリンク集を作るときは、共通のタグを決めておいてそのタグでリンクをさらってくればよい。
(例:http://del.icio.us/biwanoin/lutheir lutheirが付いたリンク )他のタグはあまり気にしていない。射影しているようにも思える。