Ruby on Rails2.1やってみた。
rubyが大分使えるようになってきたので、Ruby on Railsにチャレンジしてみた。
vmware上にCentOSが入っているので、そちらに環境を作ってみた。
準備
Railsのダウンロードページにいくと、手順が表示されています。
http://www.rubyonrails.org/down
まずはrubyを。これは大丈夫。次にrubyのパッケージ管理ツールであるRubyGems。これはまだ準備してなかったのでCentOS上でfirefoxを起動し、RubyForge(http://rubyforge.org/frs/?group_id=126)よりrubygems-1.1.1.tgzをダウンロード。解凍後setup.rbを実行する。
tar xvzf rubygems-1.1.1.tgz ruby rubygems-1.1.1/setup.rb
次はRails。このコマンドでインストールできる。
gem install rails --include-dependencies
ついでにRailsでよく使われるのがMySQLらしいので、mysqlも入れてみた。
yum install mysql-server
早速MySQLにアクセスしようとすると、こんなエラーが出ました。
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
これはMySQL自体が起動していないことが理由でした。サービスを起動しておきましょう。
/etc/rc.d/init.d/mysqld start
アプリケーションの作成
まずはアプリケーションを作ります。アプリケーションルートとなる名前を決めたら次のコマンドを実行します。
rails アプリケーション名 -d mysql
アプリケーション名に指定したディレクトリが出来ました。
次にDBの準備。
mysql -u root
でMySQLにログインし、データベースを作成。データベースは3種類作成する必要があるようです。「本番用(production)」「開発用(development)」「テスト用(test)」のそれぞれについて、以下のコマンドを実行します。
create database アプリケーション名_データベース種類 default character set utf8;
■追記(2008 6/17)
rake db:create:allを実行するとconfig/database.ymlの内容で3点セットを自動生成してくれるみたいです。
次は実際のモデルを作成します。
Railsを使ってちょっとしたプロジェクト支援ツールを作ろうと思っているので、とりあえずProjectクラスとSubProjectクラスを定義します。この2つの関連としてはProjectがSubProjectを複数保持するような1対多。
- Projectクラスの情報として、プロジェクト名、プロジェクトの説明、開始日、終了日
- SubProjectクラスの情報として、プロジェクト名、プロジェクトの説明、プロジェクトID(外部キー)
これらの定義に従って生成するには以下のようにします。
ruby script/generator scaffold project name:string description:text from:date to:date ruby script/generator scaffold sub_project name:string description:text project_id:integer
実はこれでmodelクラスだけでなく、controllerクラスやCRUDの画面、DB定義まで出来てしまうのです。では早速DBにテーブルを作成してみます。
rake db:migrate
最後にProjectとSubProjectの関連が1対多になるようにProjectクラスの定義を編集します。自動生成されたapp/model/project.rbを開くと以下のようになっているので、
class Project < ActiveRecord::Base end
定義を追加しておきます。
class Project < ActiveRecord::Base has_many :sub_projects end
動作確認
それではサーバーを起動してみます。
ruby script/server
javaでいうtomcatですかね、RailsをインストールするとWEBRickというサーバーが利用できるようになります。3000ポートで起動するらしいので「ttp://localhost:3000/projects」でアクセスしてみます。
こんな画面が表示されます。今はまだデータが何もありません。「New Project」リンクをクリックしてデータを登録します。型が日付だと入力がプルダウンになるんですねぇ。
適当に入力項目を埋めて「Create」を実行し、一覧画面に戻ります。すると先ほど登録したレコードが表示されています。
他にもこのレコードを編集する「Edit」や削除する「Destroy」があります。簡単なCRUD操作がノンプログラミングで実現できます。
テスト実施
先ほどのgenerator実行時にログが出力されるのですが、その中に興味深いものを発見しました。
create test/unit/project_test.rb create test/fixtures/projects.yml
どうやらRailsはテストケースまでテンプレートとして自動生成してくれるようです。では早速project_test.rbを見てみると、
require 'test_helper' class ProjectTest < ActiveSupport::TestCase # Replace this with your real tests. def test_truth assert true end end
となっていました。
次にprojects.ymlを見てみると、
one: name: MyString description: MyText from: 2008-06-15 to: 2008-06-15 two: name: MyString description: MyText from: 2008-06-15 to: 2008-06-15
となっており、テストデータまで用意してくれています。同様にsub_projects.ymlもテストデータが用意されています。
one: name: MyString description: MyText project_id: 1 two: name: MyString description: MyText project_id: 1
テストを実行する前に、まずはテストデータを少し書き換えます。idが自動で振られるとSubProjectの方との1対多の関係がテストしづらいのでProjectのデータのidをとりあえず1と2にします。あとプロジェクト名もせっかくなので区別がつくように編集しました。
one: id: 1 name: MyString1 description: MyText from: 2008-06-15 to: 2008-06-15 two: id: 2 name: MyString2 description: MyText from: 2008-06-15 to: 2008-06-15
次にテストケースにちゃんとしたテストを追加します。
class ProjectTest < ActiveSupport::TestCase def test_find projects = Project.find(:all) assert_equal(2, projects.size) assert_equal("MyString1", projects[0].name) assert_equal(2, projects[0].sub_projects.size) assert_equal(0, projects[1].sub_projects.size) end end
JUnitなどを知っている人であれば大体分かると思います。
定義したProjectのクラスメソッドであるfindメソッドを実行し、全件取得します。テストデータは2件なので、レコード数は2が返ることが期待されます。その後1件目を取得し、名前が「MyString1」であることをチェックします。最後に、ProjectとSubProjectの関連を調べます。0番目のものはSubProjectオブジェクトを2つ持つようにデータを編集しましたが、1番目のものは何もデータを設定していないので0のはずです。
ではテストを実行します。
rake
これで全テストが実行されます。
このテストだけ実行したい場合は次のようにします。
ruby unit/project_test.rb
これを実行すると次のように表示されました。うまくいったようです♪
Loaded suite unit/project_test Started . Finished in 0.178636 seconds. 1 tests, 4 assertions, 0 failures, 0 errors
JavaだとDBUnitというツールで同様のことが実現できますが、最初からある程度テストデータまで作ってくれているというのは驚きです。
あと、irbと同じ感覚で使えるscript/consoleがあります。
ruby script/console
とすると、対話モードになるので、
p1 = Project.new(:name=>"サンプルプロジェクト") p1.save
と入力すると、実際にDBにレコードがinsertされます。
なお、ここでinsertされる先のdatabaseはdevelopment環境です。サーバーを起動してブラウザ上で作成したデータもdevelopmentにレコードがinsertされていました。テストで利用するdatabaseはtestとなるようです。
とりあえず今日はここまで。