2008年05月06日

Rubyでファイルアップロード(サーバ側処理)

シンプルにブラウザから、アップロードされたファイルをWebサーバのc:\\usr配下に
保存します。

環境:
・WindowsXP SP2
・Ruby 1.8.6

●upload.html・・・ファイルアップロードフォームがあるHTML

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<title></title>
</head>
<body>
<form action="/cgi-bin/upload.rb" method="POST" enctype="multipart/form-data">
<input type="FILE" name="upload_file" size="20">
<input type="submit" value="送信">
</form>
</body>
</html>


●upload.rb・・・ファイルアップロードCGI

require "cgi"

OUTPUT_DIR = "c:\\usr\\"

begin
form = CGI.new

print "Content-type: text/html\n\n"

#TempfileなのかStringIOなのかを表示
print form['upload_file'].class.to_s + "<br>"

#アップロードしたファイル名
print form['upload_file'].original_filename + "<br>"

#ファイルサイズ
print form['upload_file'].size.to_s + "<br>"

#サーバ上のOUTPUT_DIR下に保存します。
open(OUTPUT_DIR + form['upload_file'].original_filename, "w") {|fh|
fh.binmode
fh.write form['upload_file'].read
}
print "Done!"

rescue => e
print "Error!!" + e
end

posted by 台北猫々 at 22:21| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2008年05月05日

正規表現で、文字列は全て半角カタカナか?のチェック(Ruby編)


UTF-8対応です。



# -* coding: UTF-8 -*-
#全て半角カタカナか?
#Rubyの正規表現で、渡された文字列が全て半角カタカナかチェックします。(UTF-8向け)
#Ruby 正規表現 半角カタカナ UTF8
str = "。アイウエオカキクケコサシスセソタチツテトナニヌネノハイフヘホマミムメモラリルレロヤユヨワン゚";
if str =~ /^(?:\xEF\xBD[\xA1-\xBF]|\xEF\xBE[\x80-\x9F])+$/
puts Kconv.tosjis("すべてが半角カタカナである")
else
puts Kconv.tosjis("すべてが半角カタカナではない")
end
#↓
#"すべて半角カタカナである"


※標準出力をutf8→SJISに変換しているのは、開発環境がWindows+Eclipseの都合です。Windows+Eclipseのコンソールは、SJISエンコーディングオンリーなので。

posted by 台北猫々 at 09:08| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2008年04月24日

正規表現で、文字列は全て全角カタカナか?のチェック(Ruby編)


UTF-8対応です。



# -* coding: UTF-8 -*-
require 'kconv'

str = "アイウエオワイウエオン"
if str =~ /^(?:\xE3\x82[\xA1-\xBF]|\xE3\x83[\x80-\xB6])+$/
puts Kconv.tosjis("すべてが全角カタカナである")
else
puts Kconv.tosjis("全角カタカナでない文字がある")
end


posted by 台北猫々 at 20:43| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2008年04月15日

正規表現で、文字列は全て平仮名か?のチェック(Ruby編)


UTF-8対応です。



# -* coding: UTF-8 -*-
require 'kconv'

str = "あいうえおわいうえおん"
if str =~ /^(?:\xE3\x81[\x81-\xBF]|\xE3\x82[\x80-\x93])+$/
puts Kconv.tosjis("すべてが全角ひらがなである")
else
puts Kconv.tosjis("すべてが全角ひらがなではない")
end



※標準出力をutf8→SJISに変換しているのは、開発環境がWindows+Eclipseの都合です。Windows+Eclipseのコンソールは、SJISエンコーディングオンリーなので。

posted by 台北猫々 at 19:31| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2008年04月08日

Ruby DE MySQL For WindowsXP

Rubyでデータベースのデータ移行ツールを作ろうと思いまして、MySQLの操作方法を調べたのですが、なかなか散文的なものが多いですね。なのでメモしておきます。

環境:
WindowsXP SP2
XAMPP 1.6.6a (MySQL 5.0.51)
Ruby 1.8.6

新規にインストールするもの
・Ruby/DBI
・MySQL/Ruby

「Ruby/DBI」はデータベースを透過的に扱うための抽象化層で、「MySQL/Ruby」は、各データベースが提供するのアクセスAPIを呼び出すドライバ層になります。

実際には、「MySQL/Ruby」だけでも操作は可能だそうですが、折角抽象化モジュールが提供されているので、「Ruby/DBI」も使用することにしました。

手順は以下のようになります。
(1)Ruby/DBIのインストール
(2)MySQL/Rubyのインストール
(3)libmysql.dllの場所をPATHに通す。

以下、詳細
============================
(1)Ruby/DBIのインストール
http://rubyforge.org/projects/ruby-dbi/からRuby/DBIのモジュールをダウンロードして適当なフォルダに展開(↓ではCドライブ直下に展開)して、DOSプロンプトから↓のようにコマンド
を実行して、インストールします。

C:\dbi-0.2.0>ruby setup.rb config --with=dbi,dbd_mysql
entering config phase...
config done.

C:\dbi-0.2.0>ruby setup.rb setup
entering setup phase...
setting #! line to "#!c:/usr/local/ruby/bin/ruby"
setup.rb: skip bin/proxyserver(dbd_proxy) by user option
setup.rb: skip ext/dbd_sybase(dbd_sybase) by user option
setup done.

C:\dbi-0.2.0>ruby setup.rb install
entering install phase...
mkdir -p c:/usr/local/ruby/bin
install sqlsh.rb c:/usr/local/ruby/bin
setup.rb: skip bin/proxyserver(dbd_proxy) by user option
mkdir -p c:/usr/local/ruby/lib/ruby/site_ruby/1.8/DBD/Mysql
install Mysql.rb c:/usr/local/ruby/lib/ruby/site_ruby/1.8/DBD/Mysql/Mysql.rb
mkdir -p c:/usr/local/ruby/lib/ruby/site_ruby/1.8/dbi
install columninfo.rb c:/usr/local/ruby/lib/ruby/site_ruby/1.8/dbi
install row.rb c:/usr/local/ruby/lib/ruby/site_ruby/1.8/dbi
install sql.rb c:/usr/local/ruby/lib/ruby/site_ruby/1.8/dbi
install trace.rb c:/usr/local/ruby/lib/ruby/site_ruby/1.8/dbi
install utils.rb c:/usr/local/ruby/lib/ruby/site_ruby/1.8/dbi
install version.rb c:/usr/local/ruby/lib/ruby/site_ruby/1.8/dbi
install dbi.rb c:/usr/local/ruby/lib/ruby/site_ruby/1.8
setup.rb: skip ext/dbd_sybase(dbd_sybase) by user option
install done.

(2)MySQL/Rubyのインストール(RubyGemsで行います)
C:\>gem install mysql
Bulk updating Gem source index for: http://gems.rubyforge.org
Select which gem to install for your platform (i386-mswin32)
1. mysql 2.7.3 (mswin32)
2. mysql 2.7.1 (mswin32)
3. mysql 2.7 (ruby)
4. mysql 2.6 (ruby)
5. Skip this gem
6. Cancel installation
> 1
Successfully installed mysql-2.7.3-mswin32
Installing ri documentation for mysql-2.7.3-mswin32...
Installing RDoc documentation for mysql-2.7.3-mswin32...
While generating documentation for mysql-2.7.3-mswin32
... MESSAGE: Unhandled special: Special: type=17, text=""
... RDOC args: --op c:/usr/local/ruby/lib/ruby/gems/1.8/doc/mysql-2.7.3-mswin32/
rdoc --exclude ext --main README --quiet ext README docs/README.html
(continuing with the rest of the installation)

(3)libmysql.dllの場所をPATHに通す。
XAMPPをデフォルトインストールしていると、「C:\xampp\mysql\bin」にlibmysql.dllはあるので、環境変数PATHに「C:\xampp\mysql\bin」を追加します。

セットアップ完了!!
=============================

DBIの使用方法は↓のサイトなどが参照になるかと思います。

「Ruby DBI モジュールを使う」
http://www.jiubao.org/ruby-dbi/ruby-dbi.html#TOC_16

#一応サンプル的なものは↓
require 'dbi'

dbh = DBI.connect('DBI:Mysql:test', 'user', 'password')

sth = dbh.prepare('select * from simple')
sth.execute

while row=sth.fetch do
p row
end

sth.finish

dbh.disconnect


※ちなみに、
libmysql.dllがPATHに無い場合のエラー
c:/usr/local/ruby/lib/ruby/site_ruby/1.8/dbi.rb:368:in `load_driver': Could not load driver (no such file to load -- c:/usr/local/ruby/lib/ruby/site_ruby/1.8/dbd/Mysql) (DBI::InterfaceError)
from c:/usr/local/ruby/lib/ruby/site_ruby/1.8/dbi.rb:233:in `_get_full_driver'
from c:/usr/local/ruby/lib/ruby/site_ruby/1.8/dbi.rb:219:in `connect'
from mysql_test.rb:4


良かったらクリックお願いします→banner_01.gif
posted by 台北猫々 at 20:58| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2008年03月21日

CSVファイル読み込み処理

RubyでCSVファイル読み込み処理


require 'csv'

class CsvFileReadSkeleton
def read(filename)
csv = CSV.open('c:\\okinawa.csv', 'r')
csv.each_with_index {|elements, index|
puts "Row Number=>#{index+1}"
elements.each { |element|
puts "#{element}"
}
}
rescue => e
print "Error!!" + e
end
end

r = CsvFileReadSkeleton.new
r.read("c:\\okinawa.csv")



良かったらクリックお願いします→banner_01.gif
posted by 台北猫々 at 23:38| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2008年03月14日

PDFファイルダウンロード

Ruby(CGI)でPDFファイルダウンロードを行います。
ダウンロードダイアログを表示しないで、AcrobatReaderプラグインで開いちゃいます。


#!"C:\usr\local\ruby\bin\ruby.exe"
require 'cgi'

def download(filename)

open(filename) {|fp|

basename = File.basename(filename)

param = {
'Content-Type' => "application/pdf",
'Content-Length' => fp.stat.size,
'Expires' => 0,
'Cache-Control' => "must-revalidate, post-check=0,pre-check=0",
'Pragma' => "private",
'Content-Disposition' => "inline; filename=\"#{basename}\""
}

cgi = CGI.new
cgi.out(param){
fp.read
}
}

end

download('c:\\sample.pdf')




良かったらクリックお願いします→banner_01.gif
posted by 台北猫々 at 08:00| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2008年03月13日

ブロックでクローズいらず!

open("c:\\okinawaa.csv") {|f| f.each {|line| print line }}
↑のようにopenメソッドにブロックを渡すとクローズ処理はいりません。ブロックを定義することにより、ファイルハンドルのスコープが明確になり、ガベージコレクト(GC)できるようですね。

ただ、
open("c:\\okinawa.csv").each {|line| print line }
では、駄目です。クローズ処理が必要です。これだとeachメソッドにブロックを渡しているだけなので、ファイルハンドルのスコープが不明確なのですね。

ちなみに、

begin
s = open("c:\\okinawa.csv") {|f|
s = f
f.each {|line|
print line
raise "fake error!\n"
}
}
rescue => e
print "Error!!" + e
print s.closed? #=>true
end

としてブロック内で例外を発生させてみたら、ちゃんとクローズしてくれていました。なかなか賢いですね。猫


良かったらクリックお願いします→banner_01.gif
posted by 台北猫々 at 18:57| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2008年03月12日

ファイルダウンロード処理

Ruby(CGI)でファイルダウンロードを行います。


#!"C:\usr\local\ruby\bin\ruby.exe"
require 'cgi'

def download(filename)

open(filename) {|fp|

basename = File.basename(filename)

param = {
'Content-Type' => "application/octet-stream",
'Content-Length' => fp.stat.size,
'Expires' => 0,
'Cache-Control' => "must-revalidate, post-check=0,pre-check=0",
'Pragma' => "private",
'Content-Disposition' => "attachment; filename=\"#{basename}\""
}

cgi = CGI.new
cgi.out(param){
fp.read
}
}

end

download('c:\\okinawa.csv')




良かったらクリックお願いします→banner_01.gif
posted by 台北猫々 at 19:27| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2008年03月10日

正規表現で、文字列は全てASCII文字か?のチェック


# -* coding: UTF-8 -*-
require 'kconv'

str = " abcdefghijklmnopqrstuvwxyz!#$&'()[]@";

if str =~ /^[\x20-\x7E]+$/
puts Kconv.tosjis("すべてASCIIである")
else
puts Kconv.tosjis("すべてASCIIでない")
end



良かったらクリックお願いします→banner_01.gif
posted by 台北猫々 at 21:22| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2007年12月13日

":include"を試してみます。

昨日の文末に書いた":include"を試してみます。
以下のようにfindメソッドにオプションとして渡すようです。

@denpyo = Denpyo.find(params[:id], :include=>:denpyo_meisais)

で、実行してみると以下のようなSQLを実行しました。
いい感じいい感じ♪。。。って駄目じゃん!

SELECT denpyos.`id` AS t0_r0, denpyos.`denpyo_no` AS t0_r1, denpyos.`shohin_sum` AS t0_r2,
denpyos.`kingaku_sum` AS t0_r3, denpyos.`denpyo_date` AS t0_r4, denpyo_meisais.`id` AS t1_r0,
denpyo_meisais.`denpyo_no` AS t1_r1, denpyo_meisais.`meisai_no` AS t1_r2,
denpyo_meisais.`shohin_name` AS t1_r3, denpyo_meisais.`suryo` AS t1_r4,
denpyo_meisais.`kingaku` AS t1_r5
FROM denpyos
LEFT OUTER JOIN
denpyo_meisais ON denpyo_meisais.denpyo_no = denpyos.id # ←駄目じゃんな箇所
WHERE (denpyos.`id` = 1)

結合条件は、"denpyo_meisais.denpyo_no = denpyos.denpyo_no"となってほしかったのですが、Railsのポリシーとして、「参照先はPKでなくちゃ」という強固な縛りがあるようです。

一応、以下のサイトにあるようなカスタマイズをRailsに行えば、参照先列を指定できるようにすることも可能のようです。
http://wota.jp/ac/?date=20061119

「レールの外は修羅の道」合掌。。。猫
posted by 台北猫々 at 19:30| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

PK以外の列同士でリレーションを張ってみましょう。

PK以外の列(伝票番号)同士でリレーションを張ってみましょう。

has_manyには複数形を指定して、belongs_toには単数形を指定するのがミソです。この辺は作成者のこだわりを感じますね。

class Denpyo < ActiveRecord::Base
has_many :denpyo_meisais, :foreign_key => 'denpyo_no'
end

class DenpyoMeisai < ActiveRecord::Base
belongs_to :denpyo, :foreign_key => 'denpyo_no'
end

として、以下のような処理をしてみます。ここで、ステップ実行させてみました。findメソッドの呼び出し時点でテーブル結合しているのかと思っていましたが、違うようですね。

@denpyo = Denpyo.find(params[:id])
flash[:notice] = @denpyo.denpyo_meisais[0].kingaku #ここで、↓のSQLが実行されます。

[0;1mSELECT * FROM denpyo_meisais WHERE (denpyo_meisais.denpyo_no = 1)

ただ、これでは件数が増えた時に、ネットワークやDBのオーバーヘッド的に「正気ですか?」という感じなので、さらに調べてみると:includeオプションというのがあるらしいです。
posted by 台北猫々 at 00:19| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2007年12月10日

Eclipse(RadRails)でRubyをステップ実行DEデバッグ

Eclipse(RadRails)を使うと、Ruby on Railsをステップ実行して、デバッグできるのですね。動作解析するのに非常に助かります。とりあえず、やり方をメモ。

EclipseにRadRails(Aptana)がプラグインされていることを前提にします(もちろんRubyとRailsも導入済みとします)。

(1)
・ruby-debug-base
・ruby-debug-ide
を以下のようにインストールします。
gem install ruby-debug-base --include-dependencies
gem install ruby-debug-ide --include-dependencies
ruby-debug-ide.JPG

(2)
Eclipseの[Window]→[設定]→[Ruby]→[Debugger]の「Use ruby-debug library」をチェックします。
ruby-debug_eclipse01.JPG

(3)
WEBRickサーバをデバッグモードで起動します。Serverビューの「虫」マークをクリックするとデバッグモードでの起動になります。
ruby-debug_eclipse02.JPG

こんな感じに起動します。
ruby-debug_eclipse03.JPG

(4)
ブレイクポイントを設定しましょう。エディタの左側のバー(↓の図の赤点線部分)をダブルクリックするとブレイクポイントを設定できます。
ruby-debug_eclipse04.JPG

(5)
Eclipseの内部ブラウザから、WEBRickにリクエストして、Railsアプリケーションを動作させると、ブレイクポイントで一時停止して変数の内容などを参照できます!!もちろんステップ実行も可能です。
ruby-debug_eclipse05.JPG
posted by 台北猫々 at 19:09| Comment(6) | TrackBack(1) | 技術メモ(Ruby)

2007年12月08日

Ruby on Railsで単純アプリケーション開発5


def acts_as_sequenced_class
::#{self.name}
end

というのは多分ですが、acts_as_sequenced_classメソッドを呼ぶと、自インスタンス(つまりActiveRecordを継承したDenpyoMeisai)への参照を返しているのでしょう。

というのは、acts_as_sequenced_classメソッドを呼んでいる場所はこんな感じ↓になっていて、
max = acts_as_sequenced_class.maximum(position_column, :conditions => scope_condition)
acts_as_sequenced_classの戻り値から、ActiveRecord#maximumメソッドを参照しているので多分そうだと。

ちなみにRubyでは"return"を省略できるそうです(なぜ、こんな可読性低下を助長するような仕様にしているかは謎ですが)。


posted by 台北猫々 at 15:05| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2007年12月06日

Ruby on Railsで単純アプリケーション開発4

acts_as_sequenced.rbを改造してみようと思いまして、ソースをハックしてやれ!とばかりにしてみたのですが。。。

わけわかんな〜い猫

class_eval <<-EOV
include ActiveRecord::Acts::List::InstanceMethods
def acts_as_sequenced_class
::#{self.name}
end
def position_column
'#{configuration[:column]}'
end
#{scope_condition_method}
before_create :assign_next_number_in_sequence
EOV

これってなにやってるの?
思ってる以上にC,C++,Java,PHPなどとは隔たりがありますね〜

とりあえず色々調べてみると、クラスの動的定義をやっているのですね。"eval"が付いているので、そこらへんは想像できるのですが、「<<-EOV」は?なんとなくヒアドキュメント的なものかなあと思って調べてみると。一応当たっているよう。

def acts_as_sequenced_class
::#{self.name}
end

これが、わかんないんです。クラス名を付けているのかなあ?調査継続です。
posted by 台北猫々 at 21:28| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2007年12月05日

Ruby on Railsで単純アプリケーション開発3

昨日の続きになりますが、
探したところ似たようなものとして、"acts_as_sequenced.rb"というものがありました。

↓の方が作成されているものです。
http://www.depixelate.com/2006/7/19/acts-as-sequenced

↑にあるソースをコピーして、/lib/acts_as_sequenced.rbとしてコピーして使用します。

が、なぜかしらんEclipseのRadRailsでは29行目の
"#{configuration[:scope].to_s} = #{{configuration[:scope].to_s}}"
がエラーになったので、
"#{configuration[:scope].to_s} = #{configuration[:scope].to_s}"
としました。

そして、environment.rbの末尾に
require 'acts_as_sequenced.rb'
を追加しました。

さらにさらに
/app/models/denpyo_meisai.rb

class DenpyoMeisai < ActiveRecord::Base
acts_as_sequenced :column => :meisai_no, :scope => 'denpyo_no = #{denpyo_no}'
end
のように編集して、レコード追加(create)をしたところ
SELECT max(meisai_no) AS max_meisai_no FROM denpyo_meisais WHERE (denpyo_no = 1)
というSQLを自動的に発行して伝票番号毎の連番を明細番号にふってくれました。

これを改造すればできそうだなあ猫
posted by 台北猫々 at 23:28| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2007年12月04日

Ruby on Railsで単純アプリケーション開発2

さてと、間が開いてしまいました。
今調べているのが、PHPのPEAR::ADODBにあるGenID($seqName = 'adodbseq',$startID=1)のようなものがRubyにないかなあ。というところ。

(GenIDは、連番を管理するDBテーブルを生成して、呼び出す毎に連番を返してくれる優れものです。)

伝票番号はAuto Incremment列を使用しないので、GenIDのようなもので連番を生成したいのですよね。う〜んあるかなあ?

※GenID:
http://www.souken.co.jp/tech/php/adodb/docs-adodb-ja.htm#genid
posted by 台北猫々 at 21:47| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2007年11月15日

テーブル命名規約について

調べてみました。

C:\usr\local\ruby\lib\ruby\gems\1.8\gems\activesupport-1.4.2\lib\active_support\inflections.rb
にありました(私の環境ではRubyをC:\usr\local\rubyにインストールしています)。

複数形化ルールを抜粋してみました。↓

inflect.plural(/$/, 's')
inflect.plural(/s$/i, 's')
inflect.plural(/(ax|test)is$/i, '\1es')
inflect.plural(/(octop|vir)us$/i, '\1i')
inflect.plural(/(alias|status)$/i, '\1es')
inflect.plural(/(bu)s$/i, '\1ses')
inflect.plural(/(buffal|tomat)o$/i, '\1oes')
inflect.plural(/([ti])um$/i, '\1a')
inflect.plural(/sis$/i, 'ses')
inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
inflect.plural(/(hive)$/i, '\1s')
inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
inflect.plural(/(matr|vert|ind)ix|ex$/i, '\1ices')
inflect.plural(/([m|l])ouse$/i, '\1ice')
inflect.plural(/^(ox)$/i, '\1en')
inflect.plural(/(quiz)$/i, '\1zes')

なるほど、結構力技ですね。これって網羅しきれているのかなと思ってしまいますが、まあ欧米の人がやっているので大丈夫なのでしょう。

ただ、あれなんですね。これだとローマ字表記の場合は落とし穴にはまる場合もあるのですね。Railsのノリとしては、開発要件によってinflections.rbをカスタマイズするものらしいです。
posted by 台北猫々 at 20:54| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2007年11月14日

Ruby on Railsで単純アプリケーション開発1

とりあえず伝票テーブルと伝票明細テーブルのレイアウトはこんな感じでしょうか。商品マスタテーブルは、今回は除外しました。

テーブル名はRailsの規約に沿って複数形にしました。ためしにscaffoldしてみたらできたのでOKのようです。ローマ字表記でも単純に's'を付ければいいようですね(Railsのソースを今度ハックしてみよう)。

//伝票テーブル
CREATE TABLE denpyos (
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
denpyo_no VARCHAR(10) NULL,
shohin_sum INTEGER UNSIGNED NULL,
kingaku_sum INTEGER UNSIGNED NULL,
denpyo_date TIMESTAMP NULL,
PRIMARY KEY(id)
);

//伝票明細テーブル
CREATE TABLE denpyo_meisais (
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
denpyo_no VARCHAR(10) NULL,
meisai_no INTEGER UNSIGNED NULL,
shohin_name VARCHAR(128) NULL,
suryo INTEGER UNSIGNED NULL,
kingaku INTEGER UNSIGNED NULL,
PRIMARY KEY(id)
);

※伝票テーブル:伝票明細テーブル=1:N

また、従来のシステムであれば伝票番号(denpyo_no)をPKにするところですが、Railsのために"id"という列を付けています。

今までの開発経験から、「伝票番号」というのは業務的なもののためが単純な通番になることがなかったので、別途、Rails用にPK列を作りました。

これにより、思わぬところに影響が出たのですが、それはまた別の機会に・・・
posted by 台北猫々 at 22:50| Comment(0) | TrackBack(0) | 技術メモ(Ruby)

2007年09月14日

Ruby on RailsをEclipseでいこう その9 〜DBトランザクションを制御するの巻〜

データベースを扱うシステムでは、テーブル間の整合性を保障するために、AテーブルとBテーブルへの更新が両方正常に行えた段階でコミットしたい時があります。

なので、今日はRuby on Railsでのトランザクション制御について。

ActiveRecordには、"transaction"というメソッド(っていうのかな?)が用意されているので、これにトランザクション処理ブロックを渡します。

具体的には、

その7とその8で作成したモデルを例にします。
モデルの呼び出し側(コントローラー)

@bookmark = Bookmark.new(params[:bookmark])
@item = Item.new(params[:item])

Bookmark.transaction(@bookmark, @item) do
#このブロック内部が1つのトランザクションとして扱われます。
#ブロック内部でSQLエラーが発生した場合はRollBackされます。
@bookmark.save
@item.save
end


今回の例では、2つのテーブルは同一DBにあるので、トランザクションはBookmarkでもItemでも、どちらのものを使ってもOK。

補足ですが、データベース自体がトランザクションをサポートしていることが前提の機能です。なので、MySQLのMyISAMのような非トランザクションタイプのデータベースでは、使えません。

分散データベース構成の場合の整合性は・・・まあ、あまり期待しすぎてはいかんですね。

posted by 台北猫々 at 21:53| Comment(0) | TrackBack(0) | 技術メモ(Ruby)