そこで、今回はInstantRailsをバッサリと入れ替えた上で、復習を兼ねて簡単なアプリを構築してみましょう。
Windows XP にインストールしてあるInstantRailsを最新版に入れ替えます。これでRuby on Rails(RoR)のバージョンも 2.0.2 に上がりました。
プログラミングはいつものAptanaIDEで書きましょう。
ナレッジデータベースを作ろう
プロジェクトを作る
今回のテストアプリは、ナレッジデータベースです。一行程度の短い質問と、その答えのデータベスです。カテゴリ分けできるようにしておきましょう。早速、[ファイル]-[新規]-[Rails Project]でプロジェクトを作ります。名前は、knowledge としておきます。
まずデータベースの設定をしておきましょう。
knowledgeプロジェクトの、config\database.ymlを開きます。
# SQLite version 3.x # gem install sqlite3-ruby (not necessary on OS X Leopard) development: adapter: sqlite3 database: db/development.sqlite3 timeout: 5000 # Warning: The database defined as 'test' will be erased and # re-generated from your development database when you run 'rake'. # Do not set this db to the same as development or production. test: adapter: sqlite3 database: db/test.sqlite3 timeout: 5000 production: adapter: sqlite3 database: db/production.sqlite3 timeout: 5000 |
development: adapter: mysql database: knowledge username: root password: host: localhost encoding: utf8 test: adapter: mysql database: knowledge_test username: root password: host: localhost encoding: utf8 production: adapter: mysql database: knowledge username: root password: host: localhost encoding: utf8 |
ここで、MySQLにknowledgeデータベースを作っておきます。私の場合、こちらは[MySQL Administrator]というGUIツールを使っています。[カタログ]を開き、[Create New Schema]で、knowledge を作ります。
今までならここでmigrationファイルを作り、テーブルを作成してしまうのですが、RoR2.0の作法は違うようです。
先に足場を組みます。
AptanaIDE の[Generators]タブを選び、
scaffold category sort_order:integer name:string |
これはカテゴリマスタになります。RoR1.0と異なり、ここでカラムの指定をします。
sort_orderカラムは並び順の指定、nameカラムはカテゴリ名称になります。
続いて、
scaffold item category_id:integer question:string answer:string |
これで何が出来たのか、ちょっとだけ確認してみると――app\viewsのファイルは拡張子がxxx.html.erb みたいになっています。list.rhtmlはindex.html.erbだし、_form.rhtmlは無くなっています。
app\controllersのファイルも中身は変更になっているようです。
デフォルトではpagenateがありません。
respond_to do |format| format.html # index.html.erb format.xml { render :xml => @items } end |
さて、話を戻して、db\migrateの中を見ておきましょう。
001_create_categories.rb
002_create_items.rb
が出来ています。中を開けてみます。
class CreateCategories < ActiveRecord::Migration def self.up create_table :categories do |t| t.integer :sort_order t.string :name t.timestamps end end def self.down drop_table :categories end end |
def self.up の直ぐ下に、
options = { :options => "ENGINE=MyISAM DEFAULT CHARSET=utf8" } |
他に初期値の設定なども必要に応じて書けますが、今回はこのままです。
では、001_create_categories.rb を右クリックして[Run Migration]しましょう。
うまく行ったようなら 002_create_items.rb も実行します。
これで足場とテーブルが揃いました。Servers タブで、KnowledgeServer を起動します。
ブラウザで、http://localhost:3000/categories に繋いでみます。
表示されましたか? あの懐かしくも素っ気ない画面ですね。
試しに何件か追加してみましょう。
|
カテゴリの並び順を何とかする
カテゴリを新規追加するたびに自分で sort_order を手打ちするのはあんまりです。何とかしましょう。新規追加のときに、sort_order が自動的に一番最後の番号になるようにしてみます。
app\models\category.rb に、以下のように追加します。
class Category < ActiveRecord::Base def before_create begin self[:sort_order] = Category.maximum(:sort_order) + 1 rescue self[:sort_order] = 1 end end end |
カテゴリの順序を入れ替える機能を付けましょう。
一覧画面で、上下に移動可能にします。
\app\views\categories\index.html.erb に、以下を追加します。
<% for category in @categories %> <tr> <td><%=h category.sort_order %></td> <td><%=h category.name %></td> <td><%= link_to 'Up', :action => 'move_up', :id => category %> <%= link_to 'Down', :action => 'move_dn', :id => category %></td> <td><%= link_to 'Show', category %></td> <td><%= link_to 'Edit', edit_category_path(category) %></td> <td><%= link_to 'Destroy', category, :confirm => 'Are you sure?', :method => :delete %></td> </tr <% end %> |
\app\controllers\categories_controller.rb に、以下を追加します。
def move_up renum_up redirect_to :action => 'index' end def move_dn renum_dn redirect_to :action => 'index' end private def renum_up category = Category.find(params[:id]) if (category.sort_order > 1) current_id = category.id current_sort_order = category.sort_order previous_id = Category.find_by_sort_order(current_sort_order - 1) Category.update(previous_id, :sort_order => current_sort_order) Category.update(current_id , :sort_order => current_sort_order - 1) end end def renum_dn category = Category.find(params[:id]) if (category.sort_order < Category.maximum(:sort_order)) current_id = category.id current_sort_order = category.sort_order next_id = Category.find_by_sort_order(current_sort_order + 1) Category.update(next_id , :sort_order => current_sort_order) Category.update(current_id, :sort_order => current_sort_order + 1) end end |
一覧の並び順を変えましょう。
\app\controllers\categories_controller.rb に、以下を追加します。
def index @categories = Category.find(:all, :order => "sort_order") respond_to do |format| format.html # index.html.erb format.xml { render :xml => @categories } end end |
Q&A(items)の登録画面に手を入れる
http://localhost:3000/items を表示させ、new_item を押すと、こんな画面が表示されるはずです。カテゴリはIDを直打ちしなけりゃならないし、Q&Aの入力欄はちっちゃいし、気に入りませんよね。
では、app\views\items\new.html.erb を開きましょう。
まずはカテゴリの選択部分から直しましょう。
<p> <b>Category</b><br /> <%= f.text_field :category_id %> </p> |
これを
<p> <b>Category</b><br /> <%= select("item", "category_id", Category.find(:all).collect {|e| [ e.name, e.id ] }) %></p> </p> |
ドロップダウンリストになったかな?
Category.find(:all).collect の部分、以前は Category.find_all.collect みたいに書いていたんですが、これはエラーになります。RoR2では find_all や find_first は無くなり、代わりに find(:all)、find(:first) を使うようになっています。
Question欄とAnswer欄も変更します。
<p> <b>Question</b><br /> <%= f.text_field :question, :size => 60 %> </p> <p> <b>Answer</b><br /> <%= f.text_area :answer, :cols => 60, :rows => 8 %> </p> |
入力画面が決まったら、変更画面(edit.html.erb)も同様に書き換えましょう。
Q&A(items)の一覧画面を見やすくする
初期状態では、こんな感じです。見にくいです。
まずはカテゴリ表示を名称に変えます。
<td><%=h item.category_id %></td> |
<td><%=h Category.find(item.category_id).name %></td> |
また、一覧表示に Answer は要らないので、削除してください。
後は好みに応じて変更を加えれば良いでしょう。
――私の場合は、
色を付けたり、同じカテゴリが続くときには先頭のみ表示させたり。ああ、そうそう、Category.sort_order 順に並べるのがまだでしたね。
\app\controllers\items_controller.rb を開きます。
def index @items = Item.find(:all) |
def index @items = Item.find(:all, :joins => "INNER JOIN categories ON items.category_id = categories.id", :order => "categories.sort_order") |
まず、カテゴリ表示を名称に変えます。
<p> <b>Category:</b> <%=h Category.find(@item.category_id).name %> </p> |
しかし、まだ見にくいです。登録時には改行が入っていたはずのAnswerが、一つの文章に繋がって表示されています。
これは、データとしては改行が入っていても、HTMLとして表示されるときには無視されているからです。HTML表示のときに、改行を<BR>に置き換えれば良さそうです。
早速置き換え用ユーザー定義関数を作りましょう。
場所は、\app\helpers\application_helper.rb にしましょう。
module ApplicationHelper def text_to_html(text) if text text.gsub!(/</,"<") text.gsub!(/>/,">") text.gsub!(/\&/,"&") text.gsub!(/\"/,""") text.gsub!(/\'/,""") text.gsub!(/\r\n/,"<br >") return text end end end |
関数を作ったので、表示ルーチンも変更します。
<p> <b>Answer:</b> <%= text_to_html(@item.answer) %> </p> |
<table border="0" cellpadding="5"> <tr bgcolor="powderblue"> <th valign="top" align="left">Category:</th> <td valign="top" align="left"><%=h Category.find(@item.category_id).name %></td> </tr> <tr bgcolor="bisque"> <th valign="top" align="left">Question:</th> <td valign="top" align="left"><%=h @item.question %></td> </tr> <tr bgcolor="seashell"> <th valign="top" align="left">Answer:</th> <td valign="top" align="left"><%= text_to_html(@item.answer) %></td> </tr> </table> <%= link_to 'Edit', edit_item_path(@item) %> | <%= link_to 'Back', items_path %> |
さて、これで一通りの機能が揃いました。以前に作ったアプリとあんまり違わない内容になってしまいましたね。
逆に言えば、RoR1のときと殆ど同じ手順でアプリを作れることが確認できました。
まだ仕事ではホスト系のアプリやDelphiばっかりですが、いずれRoRで本格的な業務用アプリを構築したいですね。
会社に、IBM i5の新品がやってきました。旧モデルの置き換えですが、OSその他のバージョンが上がり、今までは諦めていた Ruby on Rails からの DB2 アクセスが出来るかも知れません。 i5 はようやく組み上がって火が入る状態になったところなので、RoRからの接続テストを実行するまでにはもう少し掛かりそうです。 そういえば、RoRでOracleのDBは使えるんかいな? |