TodoListTutorial
How to make a todo list program with Rails
簡単なウェブアプリケーションフレームワークを始める易しい方法
Vincent Foley (vfoleybourgon@yahoo.ca), 21 Dec 2004, rev. 4
原文: http://darkhost.mine.nu:81/~vince/rails/tutorial.html
このチュートリアルは、データベースを使う小さなアプリケーションを初めて作ろうとするユーザーを対象としてます。 短く・簡単・使えるという理由で、 とってもシンプルなTODOリスト プログラムの作成をすることにしました。 Rails のバージョンは 0.9.1、 ActionPack は 1.0.1、 ActiveRecord は 1.2.0、 ActionMailer は 0.5 を使用しています。 なにか問題があれば、私にメールをください。 このチュートリアルで出てくるクラスやメソッドの情報が知りたければ、 Rails API documentation を参照してください。
インストール
このチュートリアルでは、ウェブサーバーとして WEBrick (Rails に付いているので安心してね)、 データベースとして MySQL を使用します。 今回のアプリケーションを作るために、いくつかのソフトウェアを必要とします。
Debian/GNU Linux を使っているのなら、 Ruby on Rails サイト上の Rails On Debian ページに行き、 インストールする必要のあるパッケージの情報を得ると良いでしょう。 その他のディストリビューション、Windows や MacOS などのような OS を使っている場合は、 Gem Rails ページを訪れて、 RubyGems を使ったインストールの仕方を調べると良いでしょう。 インストールでなにか問題があったら、Freenode ネットワークの #rubyonrails IRC チャネルに行って、助けを求めるのも良いでしょう。
テーブルを作る
Rails を無事にインストールできたら、 この文書のメインである TODO リスト プログラムの作成に取り掛かりましょう。
まず最初に、データベースモデルを考えます。 この文書は導入用のチュートリアルですから、 1つのテーブルに、たった3つの列 (id、description、done) という、 とてもシンプルなものにします。 私はとても怠惰なので、手動で SQL テーブルやデータベースを扱いたくありません。 そこで、phpMyAdminを使います。 (MacOS X ユーザーにも CocoaMySQL という素晴らしいプロダクトがあります。) しかしながら、利便性のために、データベースとテーブルを作成する SQL クエリを置いておきます。
-- Create the database CREATE DATABASE `todo` ;
-- Create the table CREATE TABLE `todos` ( `id` INT NOT NULL AUTO_INCREMENT , `description` VARCHAR( 100 ) NOT NULL , `done` TINYINT DEFAULT '0' NOT NULL , PRIMARY KEY ( `id` ) );
このように、TODO 項目は、ユニークな id と、description と、その項目が完了しているかどうかを表す done フラグを持ちます。 (余談になりますが、Rails を使う場合は、テーブルのプライマリキーとして 'id' を常に使うことを強く推奨します。とても役立ちます。)
さて、テーブルは出来たら早速プロジェクトを始めましょう。 適当なディレクトリに移動して、次のコマンドを実行してください。
$ rails Todo
こうすると、ディレクトリとファイルを作成したり、パーミッションを設定したりといった、長ーいリストが出力されるはずです。 終わったら (2度実行してはいけませんよ)、新しく作成されたディレクトリに入りましょう。
さて、メインの設定ファイル config/database.yml を編集しましょう。最初はこうなっているはずです。
development: adapter: mysql database: rails_development host: localhost username: root password:
test: adapter: mysql database: rails_test host: localhost username: root password:
production: adapter: mysql database: rails_production host: localhost username: root password:
私達のデータベースが使えるように database.yml を変更しましょう。 development セクションをこのように変更してください。
development: adapter: mysql database: todo host: localhost username: root password:
さあ、これで私達の Rails アプリケーションが MySQL データベースを使えるでしょう。 もし MySQL の設定を変更していたら、合わせて username と password 項目を変更してくださいね。 MySQL にユーザーを追加する方法は、MySQL のドキュメントを参照してください。
コーディング
始めの一歩
次のステップは、アプリケーションのモデルとコントローラーを作ることです。 そのために、script/ ディレクトリに generate というコマンドがあります。 こういう風に実行してください:
$ ruby script/generate model Todo $ ruby script/generate controller todo
モデル名は大文字で始めなければなりません。 そして、慣例として、モデル名とテーブル名は同じにするべきです。 (例えば、テーブル名が todos の場合は、モデル名は Todo とします。)
さて、モデルにコントローラーを "link" しましょう。 app/controllers/todo_controller.rb を開いて、このように変更してください:
class TodoController < ApplicationController model :todo end
これはとてもわかりやすいですね! TodoController クラスのモデルは :todo だとすぐわかります。 :todo は、Ruby のシンボルです。 (モデル名を小文字にし頭にコロンをつけます。)
さあ、WEBrick サーバーを起動して、私達のアプリケーションを試してみましょう。 /Todo ディレクトリに移動し、以下のようにコマンドを実行してください:
$ ruby script/server
これで、開発モードの WEBRick サーバーがポート 3000 で立ち上がりました。 ブラウザで、 http://localhost:3000 を開くと、基本設定が成功したことを知らせる Congratulations ページが開くはずです。 しかし、実はこのメッセージは、私達へ向けたものではなく、 Apache を適切に設定した人へ向けたものです。 なにせ WEBrick は、設定不要ですから。
オプションを参照するために -h フラグが使えます。
コントローラーとアクション
すばらしい! しかし、これは私達が求めるものじゃありません。 アプリケーションを動かしたいんでした! さあ、 todo/
URL の末尾に付け加えましょう。 そうすると、どうなるでしょうか?
なんと表示されていますか? あー、index アクションがないと言われていますね。(index はコントローラーのデフォルトアクションなのです。) ついでにいうと、Rails のアクションとはコントローラーのメソッドのことです。 さて、どうしたらこの問題を解決できるでしょう? app/controllers/todo_controller.rb を開いて、model :todo 行の下に、下記のコードを加えてみてください。
def index end
これは空のメソッド定義です。 Rails では、Ruby のメソッドはアクションとなります。 そして今、 index アクションがあります。どうなるでしょう? 答えはブラウザをリロードして確認してください。
え、テンプレートがない? なにそれ? 正常に表示するためには、アクションはあるけど、何かがたりないことを示しています。 じゃあ、修正しましょう。 それには、 render_text を使用します。 index メソッドをこのように変更してください。
def index
render_text("This is the index")
end
さあ、もう1度ページをリロードして、どうなるか見てみましょう。
Scaffolding
うっひょー! 動いた! けど、ToDo 管理するには、ちょっとひどい出来じゃない? もうちょいやってみましょうか、 index メソッドを削って、 そこに次の行を挿入してください。
scaffold :todo
scaffold っていうのは、データベースへの簡単なインターフェイスを自動で作成してくれるメソッドのことです。
<i>:todo</i> は、モデル名に対応するシンボル (Ruby のシンボルはコロンで始まる) です。 index ページをリロードするとどうなりますか?
まだデータは入れていないので、何も表示されませんが、 この新しいページはテーブルの全てのエントリーを表示しているのです。 scaffold は new、edit、destroy、list、show、index といった様々なアクションを作りだします。 index は単に list へリダイレクトするだけです。 list はデータベースの全ての項目を表示します。 show はそのうち1つだけ表示し、 new は新しい行を作成し、 edit は行を更新することができます。
scaffold の生成
scaffold するもう1つの方法は、コントローラーとビューに実際のコードを書き込むことです。 generate スクリプトは、 あなたのコントローラーとビューにコードを丸ごと生成するために、 scaffold アクションを含んでいます。 下記のコマンドで使用することができます。
$ ruby script/generate scaffold Todo
このチュートリアルが終わったらチェックしてみてください。
scaffold :todo 行で良しとしておきましょう。
項目の表示: part I
scaffold する時の問題は、汎用的すぎて、ToDo リスト管理ではいい具合に動いてくれないということです。 現状は、新しい項目を追加するとき、description も done フラグも入力しないといけません。 だけど、追加するとき done フラグはなくすべきです(ですよね?)。 ユーザーにそんな情報を入力させる必要はありません。 そんでもって、ユーザーに数字を入力させるのって、なんか変ですよね。 チェックボックスの方が良いと思いませんか? というわけで、独自のアクションを書いて、アプリケーションをもっと使いやすくしましょう。
ファイルから scaffold 行を削って、入力フォームを変更し、 独自メソッドを追加することにしましょう。簡単ですよ。
まず最初に、まとめて ToDo 項目を見ることができるように list を作りましょう。 app/controllers/todo_controller.rb ファイルを開いて、メソッド定義を追加します。
def list end
http://localhost:3000/todo/list をブラウザで開いてみてください。
scaffold がページから取り除かれているのがわかると思います。 しかし、"template missing" になってしまいました。 このテンプレートがないとはいったいどういうことでしょう? それは、アクションを表示するファイルがない、ということです。 app/views/todo/ の中で、list.rhtml (.html じゃありませんよ。.rhtmlです) という名の空のファイルを作成し修正を施しましょう。 これで、ブラウザをリロードすれば、空白ページが表示されるはずです。 このビューの名前は、連携させたいアクションと一致するものでなければなりません。
さあ、どうやって入力フォームをこのページに追加すれば良いでしょうか? では、list.rhtml にコードを加えてみましょう。 このコードを list.rhtml にコピーしてください:
<html>
<head>
<title>My todo list</title>
</head>
<body>
<% @items.each do |@item| %>
<%= @item.description %>
<br />
<% end %>
</body>
</html>
そして、app/controllers/todo_controller.rb 中の list メソッドも変更します:
def list @items = Todo.find_all end
さあ、ブラウザをリロードしてみましょう。
scaffold で遊んでるときに、いくつか ToDo 項目を加えていたら、それらが表示されます。 そうでなかったら、 http://localhost:3000/todo/new ページに移動して ToDo 項目を追加しましょう。
さて、ここで何をしたか明らかにしましょう。 理解するべきところは1行だけです。 つまり、todo テーブルの中の全ての列を探し出し、 @items というインスタンス変数 (頭に @ がつきます) に入れたことです。
ビューにあるのは、 極めて一般的な HTML コードです ― body の中の妙ちくりんな3行を除けば。
といったタグは、ERb タグです。 そして、その間には Ruby コードが挟まっています。 この2つの違いは、<%= %> は HTML ドキュメントに値を挿入しますが、<% %> はそうでないということです。
まず1行目。ビューはアクションメソッドの内側で宣言されたインスタンス変数へアクセスできます。 こうして @items にアクセスできるというわけです。 #each という Ruby の仕組みを使って、 @items の全ての要素に順次アクセスし、@item に代入できます。
次の行は ToDO 項目の詳細を表示しています。 description は動的に生成されたメソッドで、 @item が todo モデルのインスタンスであり、 todo テーブルには description 列があることから生成されます。 もし、テーブルに <i>chunky_bacon</i> なる列があれば、@item.chunky_bacon と呼び出すことができます。 もし、description を呼べなかったら、オブジェクトの内容を表示できず、#<Todo:0x404ca038> といったひどく使い勝手の悪い表示になります。
最後に、対応する ERb タグの中で end を使ってループを閉じます。
OK、ToDo 項目が完了しているか、そうでないかの見栄えを良くしよう。 前に言ったように、ToDo 項目の詳細の前に、ちょっとしたチェックボックスがあればきっと素敵だ。 よし、必要なのは、ToDo 項目が完了しているとき (done フィールドに 1 がセットされているとき) にはチェックされていて、完了してないとき (done に 0 がセットされているとき) はチェックされてないヤツだ。 幸運にも、Rails は ActionView で check_box というメソッドを提供してくれている。 app/views/todo/list.rhtml を再び開いて、ToDo 項目の詳細の前に、この行を追加してみようじゃないか。
<%= check_box("item", "done") %>
この行はどういうことでしょう? check_box に与える文字列は、何か取ってくるための変数 (この場合は @item ) と、求める情報を得るためのメソッドです。 check_box
@item.done が 0 より大きい場合、自動的に HTML コードに "checked" フィールドを入れてくれます。 ページをリロードすると、このように見えると思います。
いい感じですねー、けど、@item.done が 1 を返したときはどうなるんでしょう? 調べてみましょう。 scaffold がしてくれたように、自動的に編集ビューへのリンクを追加することから始めます。 app/views/todo/list.rhtml の @item.description 行の後に、次の行を付け加えてください。
<%= link_to("Edit", :action => "edit", :id => @item.id) %>
よし、この行を説明しましょう。 link_to は、ハイパーリンクを作成します。 最初の引数は、画面に表示されるラベル (HTML の <a> </a> タグに挟まれる部分)です。 残りの引数は、オプションの指定です。 :action => "edit" は、コントローラーの edit アクション (URL が http://localhost:3000/todo/edit となる) を指定しています。 :id => @item.id は、編集したい項目が何かを、 項目の id を与えて、 edit アクションに伝えるためのものです。 (URL は http://localhost:3000/todo/edit/''x''、x は項目の id となります。) さあ、画面がどうなったか見てみましょう。
Edit リンクをクリックし編集ページに移動します。そして done フィールドを 0 から 1 に変更します。 さらに、Update ボタンを押してください、最後に、一覧ビューに戻るために back リンクをクリックします。
できました! 私達のチェックボックスは、完了してるか否かに、完全に対応しました。
新規項目
done フラグの値をチェックするだけで変更を行うチェックボックスを作成するのはあとまわしにして、 今から、新しい ToDo 項目を追加する方法を見てみましょう。 項目は基本的に短い文なので、新しい入力フォームを追加するのに、ページを丸ごと作成する必要はありません。 だから、list ビュー (list.rhtml ファイル) に、入力フォームを置いてみましょう。
ビューに下記のように追加しましょう。 <% end %> 行の下です:
<hr size=3>
<form method="post" action="add_item">
New item:
<%= text_field("new_item", "description") %>
<input type="submit" value="Add item">
</form>
こうして、新規項目を入力する簡単なフォームをページ下部に加えます。 ERb コードと HTML コードが、いかに調和しているか注目してください。 text_field は、テキスト入力フィールドを簡単に作るための FormHelper メソッドです。 テーブルからデータをロードすることができ、簡単に新たなデータを追加することができます。(これからすぐにやります。) 最初の引数はインスタンス変数で、次の引数はフィールドです。 コントローラーにそのような変数が作成され、次の引数をフィールドとして持っています。 そのフィールドの値はテキスト部分に引き渡されます。 そのような変数を作成しなければ、欲しいものが空っぽになってしまいます。 しかし、Add item ボタンをクリックするとき、 <i>new_item</i> というキーを持った @params ハッシュテーブルが作成されます。 @params はフォームアクションで送られるデータを含んだ変数です。 @params の中身を表示するアクションを作ってみましょう。 次のメソッドをコントローラーに加えてください。
def add_item render_text @params.inspect end
一覧ページをリロードしてください。そして、テキストを入力し、Add item ボタンを押してください。
これが @params の中身です。 text_field で指定した new_item と description がわかりますか? それでは、実際に項目を追加するように add_item を変更してみましょう。 render_text 行の代わりに、このコードを書いてください。
def add_item # Todo の新しいインスタンスを作成します、つまり、新しい項目を作成 item = Todo.new # 項目のフィールドは "new_item" というハッシュにセットされているはず item.attributes = @params["new_item"] # データベースに格納してみる if item.save # 成功したら一覧ページへ戻る redirect_to(:action => "list") else # じゃなきゃ、エラーを表示 render_text "Couldn't add new item" end end
うぉぅ、メソッドがだんだん大きくなって参りました! で、これからどうします? えー、プログラムのコメントを読んでください。
さて、こうして項目を付け加えられるようになって、今度は削除したくなったはず。 (古くなったり、しなくて良くなった定型作業とかを。) 項目の削除はそんなに難しくない。 app/views/todo/list.rhtml ビューを開いて、Edit の下に、次の行を付け加えてみよう。
<%= link_to("Destroy", :action => "destroy", :id => @item.id) %>
これはもう説明する必要ないでしょ? だって、ほとんど同じ Edit 行が上にあるんだから。 もし、思い出せないなら、Edit がどう動くか復習してね。
んじゃ、またコントローラー (app/controllers/todo_controller.rb) に付け加えようか:
def destroy
item = Todo.find(@params["id"])
begin
item.destroy
redirect_to(:action => "list")
rescue ActiveRecord::ActiveRecordError
render_text "Couldn't destroy item"
end
end
こりゃまた、ばか正直でわかりやすいね。 削除したい項目を選んで (項目のユニーク id を使う)、 destroy してみる。
削除できたら一覧画面にもどる、できなかったらユーザーに知らせる、というわけだ。
この削除メソッドには1つ問題があります、というのは、項目を本当に削除するのか問い合わせないということです。 app/views/todo/list.rhtml
destroy 行を変更して修正しましょう:
<%= link_to("Destroy",
{ :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: #{@item.description}") %>
さて、何を変更したのでしょう? まず、既にあった引数を括弧で囲みました。 そして、<i>html_options</i> の1つである :confirm を使いました。 :confirm は、"Yes/No" ボタンのペアを出す小さな Javascript です。 ユーザーが "Yes" を押すと Rails はリンクを表示し、"No" を押すと、なにも起こりません。 ちょっと見てください:
イェイ! もうツケを払わないですむぞ!
完了フラグの変更
よし、つぎの仕事は done チェックボックスを動くようにしよう。 これをするには、ちょっとだけ JavaScript を使う必要がある。 app/views/todo/list.rhtml の check_box 呼び出しを変更してみよう:
<%= check_box("item", "done",
"onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") %>
その JavaScript を使ってるところは、"onclick" のところだ。 指定した URL へ、ブラウザがつれて行ってくれます。 その指定は、/todo/toggle_check/#{@item.id} というところです。 もし忘れていなければ、todo がコントローラー、<i>toggle_check</i> がアクション (つまり toggle_check メソッドが必要)、そして、 #{@item.id} が項目のユニーク id をもつ変数だとわかるでしょう。 HTML ソースはこうなるでしょう (項目 id が 2 のとき):
<input checked="checked" id="item_done" name="item[done]" onclick="document.location.href='/todo/toggle_check/2'" type="checkbox" value="1" />
さて、データベースに変更を加えるために、toggle_check を書く必要があります。 めっちゃ簡単ですよ、もし完了フラグが 1 だったら 0 にし、0 だったら 1 に変えるだけです。
def toggle_check
item = Todo.find(@params["id"])
# change the done flag. ActiveRecord
# will automatically do the boolean/int
# conversion.
item.done = !item.done?
if item.save
redirect_to(:action => "list")
else
render_text "Couldn't update item"
end
end
簡単でしょ? 今まで書いてきた他のメソッドとよく似ているので、これ以上説明する必要があるとは思えないなぁ。 ブラウザをリロードして、このちょっとしたチェックボックスがどう動くか見てみよう。 スクリーンショットは出さないよ。チェックボックスをクリックしている瞬間を撮るのは難しいからね。
項目の表示: part II
さて、これで、新しい項目を追加したり、素敵な scaffold ページ で編集したり、削除したり、チェックしたりできるようになった。 今度は表示を再考してみよう。 今、項目は全て id 順にいっしょに表示されている。 紙のノートならこれでイイけど、コンピューターならソートも簡単だよね。 そこで、これから 2 つのことをしようと思う:
- 詳細順に項目を並べる (アルファベット順)
(app/controllers/todo_controller.rb) コントローラーで、list メソッドを若干修正しましょう。こういう風にです:
def list
@not_done = Todo.find_all("done = 0", "description")
@done = Todo.find_all("done = 1", "description")
end
find_all の引数は、一つ目はフィルタです。nil の場合、フィルタなしとなります。 この場合、@not_done には done の値が 0 のものだけ、 @done には done の値が 1 のものだけ入ります。 二つ目の引数は SORT BY です。もしなにもなければ、id が仮定されます。
しかしながら、この部分はコントローラーよりもモデルにより関連してるので、完了項目・そうでない項目を探し出す処理は、多分、モデルにあった方が良いでしょう。 というわけで、app/models/todo.rb を開いてこれらのメソッドを追加してください:
def self.find_not_done
find_all("done = 0", "description")
end
def self.find_done
find_all("done = 1", "description")
end
これらは、done フラグが一致する項目を探し出して description の順に並べかえるクラスメソッド (self. が頭につきます) です。 これでコントローラーやビューの中で使うことができます。 コントローラーの list メソッドを以下のように変更してみましょう:
def list @not_done = Todo.find_not_done @done = Todo.find_done end
処理をあるべきところ・モデルに押し付けましたが、変更前と同じように動きます。
さあ、これで我々がほしい値をもった 2 つの入れ物があります。表示してみましょう。
このパートでは、わかりやすいが醜い方法で書いてみます。新しくなったファイル全体です:
<html>
<head>
<title>My todo list</title>
</head>
<body>
Not done:<br />
<% @not_done.each do |@item| %>
<%= check_box("item", "done",
"onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") %>
<%= @item.description %>
<%= link_to("Edit", :action => "edit", :id => @item.id) %>
<%= link_to("Destroy",
{ :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: #{@item.description}") %>
<br />
<% end %>
<p>
<hr size=3>
<p>
Done:<br />
<% @done.each do |@item| %>
<%= check_box("item", "done",
"onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") %>
<%= @item.description %>
<%= link_to("Edit", :action => "edit", :id => @item.id) %>
<%= link_to("Destroy",
{ :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: #{@item.description}") %>
<br />
<% end %>
<hr size=3>
<form method="post" action="add_item">
New item:
<%= text_field("new_item", "description") %>
<input type="submit" value="Add item">
</form>
</body>
</html>
そして結果:
えー、これは動くけど、ビューのなかにコードが入っているので、ひどいと思う人がいるだろう。 項目を格納する配列名が違うだけで、基本的に同じコードがありますね。 ちょっとリファクタリングしたくありません? リファクタリングはファイルをもっと短くすっきりさせます。 ビューから呼び出すメソッドを書くのには helper ファイルが使えます。 app/helpers/todo_helper.rb を開いて、このメソッドを追加してください:
def display_items(ary)
result_string = ""
ary.each do |@item|
result_string << check_box("item", "done",
"onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") + " "
result_string << @item.description + " "
result_string << link_to("Edit", :action => "edit", :id => @item.id) + " "
result_string << link_to("Destroy",
{ :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: #{@item.description}")
result_string << "<BR />"
end
return result_string
end
ビューで使うためのメソッドはテキストを返せば良い、つまり、文字列に全て突っ込んで、その文字列を返せば良い。 すると、Rails のディスパッチャーによって処理され表示される。 最初の 3 行に末尾に空白を付けているのは、要素の間に空白を入れるためです。さもなければ全部くっついてしまいます。そして、app/views/todo/list.rhtml は以下のようになります:
<html>
<head>
<title>My todo list</title>
</head>
<body>
Not done:<br />
<%= display_items(@not_done) %>
<p>
<hr size=3>
<p>
Done:<br />
<%= display_items(@done) %>
<hr size=3>
<form method="post" action="add_item">
New item:
<%= text_field("new_item", "description") %>
<input type="submit" value="Add item">
</form>
</body>
</html>
これで、かなり短くなりました。でしょ? これで、前のようにコードの重複があって、やーな感じがしてた人も喜ぶでしょう。 もし。ビューの中にコードが溢れていた場合、ヘルパーメソッドに移動することを強く考えるべきです。
項目の表示: パーシャルを使う
項目を表示するときに、もう一つの方法があります。 それは、partials を利用する方法です。 パーシャルは、ビューを内蔵した、サブ・テンプレートといえるものです。 パーシャルは、名前がアンダースコア (_) で始まるので、通常のテンプレートと区別しやすいです。 項目の表示に パーシャルをどう使えるか見てみましょう。 まず、app/views/todo/_display.rhtml (頭のアンダースコアは必須です) というファイルを作成する必要があります。
<%= check_box("item", "done",
"onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") %>
<%= @item.description %>
<%= link_to("Edit", :action => "edit", :id => @item.id) %>
<%= link_to("Destroy", { :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: #{@item.description}") %>
<br>
パーシャルを使うために、app/views/todo/list.rhtml ファイルを今から変更しましょう。 ヘルパーメソッドを呼び出す行を削除し、この 3 行をその代わりに入れてください:
# Not done section <% @not_done.each do |@item| %> <%= render_partial "display", @item %> <% end %>
# Done section <% @done.each do |@item| %> <%= render_partial "display", @item %> <% end %>
render_partial メソッドは、最初の文字列型の引数はパーシャル名 (頭からアンダースコアを取ったファイル名) で、 お次は、表示するための項目 (パーシャルを見れば、@item 変数を使うとわかりますね) です。 ブラウザをリロードすれば、前と全く同じ表示が得られるでしょう。
コレクションをループさせて、パーシャルで表示することは、 render_collection_of_partials というメソッドを使うことと同じことです。 コントローラーで、先ほど追加した行を削除し、代わりにこうしてください:
# Not done section <%= render_collection_of_partials "display", @not_done %>
# Done section <%= render_collection_of_partials "display", @done %>
そして、app/views/todo/_display.rhtml に 1 行付け加える必要があります:
<% @item = display %> <!-- この行を追加する -->
<%= check_box("item", "done",
"onclick" => "document.location.href='/todo/toggle_check/#{@item.id}'") %>
<%= @item.description %>
<%= link_to("Edit", :action => "edit", :id => @item.id) %>
<%= link_to("Destroy",
{ :action => "destroy", :id => @item.id },
:confirm => "Are you sure you want to delete this entry: #{@item.description}") %>
<br>
この行を加えた理由は 2 つあります。
- The name of an individual element when using render_collection_of_partials is that of the partial, and I think that display is a particularily bad name to represent a todo item;
- check_box を使うときは、インスタンス変数 (@ではじまる変数) を使う必要があります。それは最初の引数が、インスタンス変数を表す文字列だからです。もしインスタンス変数が使えなければ、チェックボックスが空になってしまいます。
さて、ページをリロードすれば、同じ結果が得られるはずです。
ヘルパーとパーシャルと、どちらが良いでしょうか? 場合や人によると思いますが、パーシャルは最近 Rails に付け加えられたもので、 ヘルパーやさっきのようなゴチャゴチャしたテンプレートを使わないで、表示物を作ることができます。
Thanks
このチュートリアルの作成を手伝ってくれた下記の人たちに感謝したいと思います。 David Hansson-Heinemeier Rails の作者ー:)。 #rubyonrails Rails の IRC チャンネルにいる人はみんなとっても親切で面白くて、私が Rails を始めるのにあたって本当に色々と手伝ってくれました。 Jamis Buck はページの外見を良くするために適切な Ruby スクリプトを提供してくれました。 Jonathan Paisley は dispatch.servlet の -c オプションなど、素晴らしい提案してくれました。 Robert Bousquet は item.destroy のバグを指摘してくれました。 Christian Metts は partials を使うように提案してくれました。 Peter Kjær Monsson はこのチュートリアルをミラーしてくれました。 Josh Goebel は CSS に関して全面的に手伝ってくれました。
最後に、web アプリケーションを作るのにあたってほとんど知られていないこのフレームワークを試すことを決めたすべての人に大きな声でありがとうと良いたいです。そして、変なフランス系カナダ人の書いたチュートリアルを試して、それについて自分の blog に書いてくれて本当にありがとう。
私はこのチュートリアルが英語、フランス語、イタリア語、スペイン語の blog からリンクされていることを知りました。本当に本当にありがとう。
Keyword(s):
References:[FrontPage]