Create  Edit  Diff  FrontPage  Index  Search  Changes  History  Source  RSS  Note  wikifarm  Login

Rails' Wiki - TodoListTutorial Diff

  • Added parts are displayed like this.
  • Deleted parts are displayed like this.

How to make a todo list program with [[Rails|http://www.rubyonrails.org]]

'''簡単なウェブアプリケーションフレームワークを始める易しい方法'''

''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|http://api.rubyonrails.org]]
を参照してください。

! インストール

このチュートリアルでは、ウェブサーバーとして WEBrick
(Rails に付いているので安心してね)、
データベースとして MySQL を使用します。
今回のアプリケーションを作るために、いくつかのソフトウェアを必要とします。

[[Debian/GNU Linux|http://www.debian.org]] を使っているのなら、
[[Ruby on Rails|http://www.rubyonrails.org]]
サイト上の
[[Rails On Debian|http://www.rubyonrails.org/show/RailsOnDebian]]
ページに行き、
インストールする必要のあるパッケージの情報を得ると良いでしょう。
その他のディストリビューション、Windows や MacOS などのような OS を使っている場合は、
[[Gem Rails|http://www.rubyonrails.org/show/GemRails]]
ページを訪れて、
[[RubyGems|http://rubygems.rubyforge.org]]
を使ったインストールの仕方を調べると良いでしょう。
インストールでなにか問題があったら、Freenode ネットワークの #rubyonrails
IRC
チャネルに行って、助けを求めるのも良いでしょう。

! テーブルを作る

Rails を無事にインストールできたら、
この文書のメインである
TODO
リスト プログラムの作成に取り掛かりましょう。

まず最初に、データベースモデルを考えます。
この文書は導入用のチュートリアルですから、
1つのテーブルに、たった3つの列 (id、description、done) という、
とてもシンプルなものにします。
私はとても怠惰なので、手動で
SQL テーブルやデータベースを扱いたくありません。
そこで、[[phpMyAdmin|http://phpmyadmin.net]]を使います。
(MacOS X ユーザーにも [[CocoaMySQL|http://cocoamysql.sourceforge.net/]] という素晴らしいプロダクトがあります。)
しかしながら、利便性のために、データベースとテーブルを作成する
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|http://www.mysql.com]] のドキュメントを参照してください。

! コーディング
!! 始めの一歩

次のステップは、アプリケーションのモデルとコントローラーを作ることです。
そのために、'''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|http://localhost:3000]]
を開くと、基本設定が成功したことを知らせる Congratulations ページが開くはずです。
しかし、実はこのメッセージは、私達へ向けたものではなく、
Apache を適切に設定した人へ向けたものです。
なにせ WEBrick は、設定''不要''ですから。

{{attach_view("congrats.png")}}

オプションを参照するために ''-h'' フラグが使えます。

!! コントローラーとアクション

すばらしい! しかし、これは私達が求めるものじゃありません。
アプリケーションを動かしたいんでした!
さあ、
'''todo/'''

URL
の末尾に付け加えましょう。
そうすると、どうなるでしょうか?

{{attach_view("unknown_action.png")}}

なんと表示されていますか? あー、'''index''' アクションがないと言われていますね。(index はコントローラーのデフォルトアクションなのです。)
ついでにいうと、Rails のアクションとはコントローラーのメソッドのことです。
さて、どうしたらこの問題を解決できるでしょう?
'''app/controllers/todo_controller.rb'''
を開いて、'''model :todo''' 行の下に、下記のコードを加えてみてください。

def index
end

これは空のメソッド定義です。
Rails では、Ruby のメソッドはアクションとなります。
そして今、
''index''
アクションがあります。どうなるでしょう?
答えはブラウザをリロードして確認してください。

{{attach_view("template_missing.png")}}

え、テンプレートがない?
なにそれ?
正常に表示するためには、アクションはあるけど、何かがたりないことを示しています。
じゃあ、修正しましょう。
それには、
'''[[render_text|http://api.rubyonrails.org/classes/ActionController/Base.html#M000032]]'''
を使用します。
''index''
メソッドをこのように変更してください。

def index
   render_text("This is the index")
end

さあ、もう1度ページをリロードして、どうなるか見てみましょう。

{{attach_view("index.png")}}

!! Scaffolding

うっひょー! 動いた! けど、ToDo 管理するには、ちょっとひどい出来じゃない?
もうちょいやってみましょうか、
''index''
メソッドを削って、
そこに次の行を挿入してください。

scaffold :todo

'''[[scaffold|http://api.rubyonrails.org/classes/ActionController/Scaffolding/ClassMethods.html#M000011]]'''
っていうのは、データベースへの簡単なインターフェイスを自動で作成してくれるメソッドのことです。

<i>:todo</i>
は、モデル名に対応するシンボル (Ruby のシンボルはコロンで始まる) です。
''index''
ページをリロードするとどうなりますか?

{{attach_view("scaffold_index.png")}}

まだデータは入れていないので、何も表示されませんが、
この新しいページはテーブルの全てのエントリーを表示しているのです。
'''[[scaffold|http://api.rubyonrails.org/classes/ActionController/Scaffolding/ClassMethods.html#M000011]]'''
は 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|http://api.rubyonrails.org/classes/ActionController/Scaffolding/ClassMethods.html#M000011]]'''
行を削って、入力フォームを変更し、
独自メソッドを追加することにしましょう。簡単ですよ。

まず最初に、まとめて ToDo 項目を見ることができるように
'''list'''
を作りましょう。
'''app/controllers/todo_controller.rb'''
ファイルを開いて、メソッド定義を追加します。

def list
end

[[http://localhost:3000/todo/list|http://localhost:3000/todo/list]]
をブラウザで開いてみてください。

'''[[scaffold|http://api.rubyonrails.org/classes/ActionController/Scaffolding/ClassMethods.html#M000011]]'''
がページから取り除かれているのがわかると思います。
しかし、"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

さあ、ブラウザをリロードしてみましょう。

{{attach_view("custom_list.png")}}

scaffold で遊んでるときに、いくつか ToDo 項目を加えていたら、それらが表示されます。
そうでなかったら、
[[http://localhost:3000/todo/new|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|http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M000486]]'''
というメソッドを提供してくれている。
'''app/views/todo/list.rhtml'''
を再び開いて、ToDo 項目の詳細の前に、この行を追加してみようじゃないか。

<%= check_box("item", "done") %>

この行はどういうことでしょう?
'''[[check_box|http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M000486]]'''
に与える文字列は、何か取ってくるための変数
(この場合は '''@item''' )
と、求める情報を得るためのメソッドです。
'''[[check_box|http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M000486]]'''

'''@item.done'''
が 0 より大きい場合、自動的に
HTML
コードに
"checked"
フィールドを入れてくれます。
ページをリロードすると、このように見えると思います。

{{attach_view("custom_list_checkbox.png")}}

いい感じですねー、けど、'''@item.done''' が 1 を返したときはどうなるんでしょう?
調べてみましょう。
'''scaffold''' がしてくれたように、自動的に編集ビューへのリンクを追加することから始めます。
'''app/views/todo/list.rhtml''' の
'''@item.description''' 行の後に、次の行を付け加えてください。

<%= link_to("Edit", :action => "edit", :id => @item.id) %>

よし、この行を説明しましょう。
'''[[link_to|http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#M000480will]]'''
は、ハイパーリンクを作成します。
最初の引数は、画面に表示されるラベル
(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 となります。)
さあ、画面がどうなったか見てみましょう。

{{attach_view("custom_list_linkto.png")}}

Edit リンクをクリックし編集ページに移動します。そして ''done'' フィールドを 0 から 1 に変更します。
さらに、Update ボタンを押してください、最後に、一覧ビューに戻るために ''back'' リンクをクリックします。

{{attach_view("custom_list_checkbox_checked.png")}}

できました!
私達のチェックボックスは、完了してるか否かに、完全に対応しました。

!! 新規項目

''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|http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M000482]]'''
は、テキスト入力フィールドを簡単に作るための
'''[[FormHelper|http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html]]'''
メソッドです。
テーブルからデータをロードすることができ、簡単に新たなデータを追加することができます。(これからすぐにやります。)
最初の引数はインスタンス変数で、次の引数はフィールドです。
コントローラーにそのような変数が作成され、次の引数をフィールドとして持っています。
そのフィールドの値はテキスト部分に引き渡されます。
そのような変数を作成しなければ、欲しいものが空っぽになってしまいます。
しかし、''Add item'' ボタンをクリックするとき、
<i>new_item</i> というキーを持った
'''@params''' ハッシュテーブルが作成されます。
'''@params''' はフォームアクションで送られるデータを含んだ変数です。
'''@params''' の中身を表示するアクションを作ってみましょう。
次のメソッドをコントローラーに加えてください。

def add_item
   render_text @params.inspect
end

一覧ページをリロードしてください。そして、テキストを入力し、''Add item'' ボタンを押してください。

{{attach_view("params_inspect.png")}}

これが '''@params''' の中身です。
'''[[text_field|http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#M000482]]'''
で指定した ''new_item'' と ''description'' がわかりますか?
それでは、実際に項目を追加するように '''add_item''' を変更してみましょう。
'''[[render_text|http://api.rubyonrails.org/classes/ActionController/Base.html#M000032]]'''
行の代わりに、このコードを書いてください。

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

うぉぅ、メソッドがだんだん大きくなって参りました!
で、これからどうします?
えー、プログラムのコメントを読んでください。

{{attach_view("add_new_item.png")}}

さて、こうして項目を付け加えられるようになって、今度は削除したくなったはず。
(古くなったり、しなくて良くなった定型作業とかを。)
項目の削除はそんなに難しくない。
'''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|http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M000628]]'''
してみる。

削除できたら一覧画面にもどる、できなかったらユーザーに知らせる、というわけだ。

この削除メソッドには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" を押すと、なにも起こりません。
ちょっと見てください:

{{attach_view("destroy_javascript.png")}}

{{attach_view("destroy.png")}}

イェイ! もうツケを払わないですむぞ!

!! 完了フラグの変更

よし、つぎの仕事は ''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|http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M000599]]'''
の引数は、一つ目はフィルタです。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>

そして結果:

{{attach_view("done_not_done.png")}}

えー、これは動くけど、ビューのなかにコードが入っているので、ひどいと思う人がいるだろう。
項目を格納する配列名が違うだけで、基本的に同じコードがありますね。
ちょっとリファクタリングしたくありません?
リファクタリングはファイルをもっと短くすっきりさせます。
ビューから呼び出すメソッドを書くのには ''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|http://api.rubyonrails.org/classes/ActionView/Partials.html#M000112]]'''
メソッドは、最初の文字列型の引数はパーシャル名 (頭からアンダースコアを取ったファイル名) で、
お次は、表示するための項目 (パーシャルを見れば、'''@item''' 変数を使うとわかりますね) です。
ブラウザをリロードすれば、前と全く同じ表示が得られるでしょう。

コレクションをループさせて、パーシャルで表示することは、
'''[[render_collection_of_partials|http://api.rubyonrails.org/classes/ActionView/Partials.html#M000113]]'''
というメソッドを使うことと同じことです。
コントローラーで、先ほど追加した行を削除し、代わりにこうしてください:

# 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 に付け加えられたもので、
ヘルパーやさっきのようなゴチャゴチャしたテンプレートを使わないで、表示物を作ることができます。

! Links
'''Rails''':
[[Ruby on Rails|http://www.rubyonrails.org]]
[[Rails documentation|http://api.rubyonrails.org]]
[[Rails Academy|http://www.rubyonrails.org/show/RailsAcademy]]
[[Testing with Ruby on Rails|http://www.swimshark.ca/rails/testing_tutorial.pdf]] (PDF)
[[Vim syntax for eRuby|http://vim.sourceforge.net/scripts/script.php?script_id=403]]
[[Loud Thinking|http://www.loudthinking.com]]
[[#rubyonrails|irc://irc.freenode.net/#rubyonrails]]
[[The Rails mailing list|http://lists.rubyonrails.org/mailman/listinfo/rails]]


'''Ruby''':
* [[Ruby|http://www.ruby-lang.org/en]]
* [[ruby-talk|http://groups.google.com/groups?hl=en=lr==group=comp.lang.ruby]]
* [[ruby-doc|http://www.ruby-doc.org]]
* [[Programming Ruby First Edition|http://www.rubycentral.com/book]]
* [[RubyForge|http://www.rubyforge.org]]
* [[RubyGems|http://rubygems.rubyforge.org]]
* [[RubyGarden|http://www.rubygarden.org]]
! 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{{e(aelig)}}r Monsson''' はこのチュートリアルをミラーしてくれました。
'''Josh Goebel''' は CSS に関して全面的に手伝ってくれました。

最後に、web アプリケーションを作るのにあたってほとんど知られていないこのフレームワークを試すことを決めたすべての人に大きな声でありがとうと良いたいです。そして、変なフランス系カナダ人の書いたチュートリアルを試して、それについて自分の blog に書いてくれて本当にありがとう。

私はこのチュートリアルが英語、フランス語、イタリア語、スペイン語の blog からリンクされていることを知りました。本当に本当にありがとう。


! Conclusion

これでこの Rails チュートリアルはおしまいです。このチュートリアルがあなたの手助けになればと良いなと思います。質問、コメント、訂正があれば気軽に[[私|mailto:vfoleybourgon at yahoo.ca]] (訳注:誤訳等は [[babie|mailto:babie7a0 at ybb.ne.jp]]) に送ってください。あと、是非 Freenode サーバーの #rubyonrails IRC チャンネルに私達を訪ねてみて下さい。(そうして)一緒に面白いことを見つけたり、他の人を手伝たったりしましょう手伝ったりしましょう