復習を兼ねてRoR2.0
|
昨年(2007)12月に、Rails のバージョンが2に上がりました。現在の最新は 2.0.2 となっています。1系とは若干(?)仕様が異なるようで、そのままでは動かない既存アプリも出てきそうです。
そこで、今回は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
|
あれれ、デフォルトのデータベースが SQLite3 になってます。そうです、RoRバージョン2では、SQLite3がデフォルトになりました。でも、そんなの関係ねぇ、ここはいつものMySQLに変えておきます。おっぱっぴー
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
|
rakeを走らせるとtestデータベースはクリアされますので、productionデータベースとは違う名前にしておきます。
ここで、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
|
Q&A本体の足場も作ります。
これで何が出来たのか、ちょっとだけ確認してみると――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
|
見慣れないものがあります。これは、クライアントからの要求により、htmlかxmlを返す仕組みのようで、http://ほげほげ/xxx.html を要求すると通常のWEBページが、http://ほげほげ/xxx.xml を要求すると、XML形式でデータが取得できます。
さて、話を戻して、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 に繋いでみます。
表示されましたか? あの懐かしくも素っ気ない画面ですね。
試しに何件か追加してみましょう。
ここで、
http://localhost:3000/categories.xml とすると、登録したデータがXML形式で送られてきます。今のところ使い途を思いつきませんが、データ再利用の折にはきっと役に立つでしょう。
カテゴリの並び順を何とかする
カテゴリを新規追加するたびに自分で 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\new.html.erb から、sort_order 登録部分を削除しておきます。
カテゴリの順序を入れ替える機能を付けましょう。
一覧画面で、上下に移動可能にします。
\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 %>
|
move_up、move_dn を呼び出しますので、呼ばれる側を作りましょう。
\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
|
一覧表示で[Up][Down]をクリックすると―― Sort Order の順序が入れ替わりますね。希望していたのとはちょっと違う挙動です。
一覧の並び順を変えましょう。
\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>
|
size、cols、rowsの値は好きに決めましょう。
入力画面が決まったら、変更画面(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)
|
次のようにJOINして順序を指定します。
def index
@items = Item.find(:all,
:joins => "INNER JOIN categories ON items.category_id = categories.id",
:order => "categories.sort_order")
|
show をクリックしてQ&Aを表示させてみましょう。
まず、カテゴリ表示を名称に変えます。
<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
|
改行だけなら、text.gsub!(/\r\n/,"<br >") 以外は不要です。
関数を作ったので、表示ルーチンも変更します。
<p>
<b>Answer:</b>
<%= text_to_html(@item.answer) %>
</p>
|
大体良さそうですか?私は表示部をテーブル化してみました。show.html.erb の最終形は次のようになりました。
<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は使えるんかいな?
|
|
|