モデルのコードの単体テスト
モデルのコードをコントローラクラスに挿入する前に、すべてのメソッドが期待どおりに動作するかを確認するために単体テストを実施します。通常、単体テストはメソッドを個別にテストする小規模なものが望ましいのですが、ここでは、複数のテストを単体テストファイル「test/unit/wiki_test.rb」内のtest_wikiという1つのメソッドにまとめて実施します。test_wikiメソッドでは、Wikiモデルクラスのsave、find、delete、exists?の各メソッドをテストします。以下に「wiki_test.rb」ファイルから抜粋したコードを示します。
# Ensure file doesn't exist (yet) assert !File.exists?(getfullpath(@filename)) # Test save and find Wiki.save @filename, DEFAULT_TEXT assert File.exists?(getfullpath(@filename)) text = Wiki.find(@filename) assert_equal DEFAULT_TEXT, text # Test delete Wiki.delete @filename # Test exists? assert !Wiki.exists?(@filename)
ここで、データベースを使用しないRailsアプリケーションをテストするときに発生するいくつかの問題と、その解決方法について考える必要があります。通常、モデルクラスの単体テストは、Railsアプリケーションのトップレベルのディレクトリからrake test:unitsコマンド(以前のバージョンではrake test_units)を実行して開始します。このときRailsはデフォルトでデータベースに接続しようとしますが、RailsWikiアプリケーションはデータベースを使用しないので、この部分をうまく機能させるために2つの変更が必要です(詳細は、Jay Fieldsのブログ記事「Ruby on Rails Unit Tests」を参照)。
まず、lib/tasksの下に拡張子.rakeで終わるファイルを配置する必要があります。これには、本稿のダウンロードファイルに含まれている「testing.rake」というファイルを使用します。このファイルには、次のRubyコードが含まれています。
Rake::Task[:'test:units'].prerequisites.clear
次に、「test/test_helper.rb」ファイルのコードを次のように変更します。
ENV["RAILS_ENV"] = "test" require File.expand_path(File.dirname(__FILE__) \ + "/../config/environment") require 'application' require 'test/unit' require 'action_controller/test_process' require 'breakpoint'
ここでrake test:unitsコマンドを実行すると、次のような出力が生成されます。
Started . Finished in 0.094 seconds. 1 tests, 5 assertions, 0 failures, 0 errors
モデル、ビュー、コントローラのコードを統合する
Wikiモデルクラスのコーディングとテストが完了したら、モデル、ビュー、コントローラのコードを統合します。リスト2に、WikiControllerクラスの完全なコードを示します(このクラスは「app/controllers/wiki_controller.rb」にあります)。
# This is the front/main controller for the Wiki application # Author: Anil Hemrajani # Date: Feb, 2007 class WikiController < ApplicationController layout "wiki" , :except => [ :index, :print ] def initialize Wiki.basedir WIKI_DIR end def index @filelist = Wiki.find_wikis end def edit get_content end def view get_content end def print get_content end def help @filename = get_filename params[:f] # need this for other actions end # create new wiki file def create @filename = get_filename params[:f] if Wiki.exists?(@filename) flash[:error] ="File '#{@filename}' already exists; use Open instead of Create." redirect_to :action => :index else Wiki.save @filename, "" redirect_to :action => :view, :f => @filename end end # delete existing wiki file def delete if params[:f].nil? || params[:f].empty? flash[:error] = "File parameter not specified." redirect_to :action => :index else @filename = get_filename params[:f] Wiki.delete @filename redirect_to :action => :index end end # save existing wiki file def save @filename = get_filename params[:f] content = params[:c] p @filename p content Wiki.save @filename, content redirect_to :action => :view, :f => params[:f] end private def get_filename(f) f = "untitled" if (f.nil? || f.empty?) f end # load file into @content using param :f; for errors go to index page def get_content begin @filename = get_filename params[:f] @filestat = Wiki.attributes @filename @content = Wiki.find @filename rescue Errno::ENOENT => exception flash[:error] = exception redirect_to :action => :index end end end
先ほど、Railsのscript/generate controllerコマンドを実行したとき、いくつかのスタブファイルが生成されたことを思い出してください。ただし今回の例では、生成されたメソッドにコードを追加し、さらにいくつかのメソッドを追加しました。新たに追加したメソッドは、ビューに関連付けられるものではなく、他のビューから利用される特定のアクションとして機能するものです。WikiControllerには、initialize、index、edit、view、print、help、create、delete、saveというpublicメソッドが含まれています。これらのメソッドの一部を詳しく見てみましょう。
- initializeメソッド
- indexメソッド
- edit、view、printの各メソッド
WIKI_DIRプロパティを介して構成されます。Wikiファイルを必要に応じて別の適切なディレクトリの下に保存したくなった場合は、この設定だけを変更すれば済みます。WIKI_DIR = "/tmp/railswiki"
Wiki.find_wikisを呼び出して既存のWikiファイル名のリストを生成し、そのリストをインスタンス変数@filelistを介して「index.rhtml」ビューに渡します。このビューは、配列をループ処理し、処理結果をHTMLの<SELECT>ドロップダウンリストに設定します。
<select name="f">
<% @filelist.each do |file| %>
<option><%= file %></option>
<% end %>
</select>
get_contentという内部(private)メソッドを呼び出すだけです。get_contentは、リクエストされたファイルを読み込み、そのファイルの属性と内容をそれぞれインスタンス変数@filestatと@contentを介して対応するビューに渡します。以下に使用例を示します。
def get_content
begin
@filename = get_filename params[:f]
@filestat = Wiki.attributes @filename
@content = Wiki.find @filename
rescue Errno::ENOENT => exception
flash[:error] = exception
redirect_to :action => :index
end
end
get_contentメソッドは、リクエストされたファイルの内容と属性を読み込む他に、ページをインデックスページにリダイレクトし、例外が発生した場合にはエラーメッセージを表示します。エラーメッセージは、Railsのflash機能(実体はアプリケーションエラーを格納するハッシュ)を使用して設定します。
コントローラがビューにコントロールを渡すと、ビューは単にインスタンス変数@contentの内容を表示します。例えば、「view.rhtml」テンプレートに含まれているファイル全体として1行しかないコードでは、Wikiファイルの内容を表示するだけでなく、表示する前に内容をto_htmlというヘルパーメソッドを使用して変換します。
<%= to_html @content %>
to_htmlヘルパーメソッドは、Railsが生成するヘルパーモジュール「app/helpers/wiki_helper.rb」ファイル内にあります(ヘルパーモジュールはビューで使用するメソッドを作成するのに便利です)。また、このファイルは、未加工のWikiファイルをHTMLに変換する手順を含み、前に説明したRedClothというgemの動作が開始する場所でもあります。以下に、「wiki_helper.rb」に含まれる、このコードの内容を示します。
require 'redcloth' module WikiHelper # parse and return data as HTML def to_html(rawtext) return "" if rawtext.nil? r = RedCloth.new rawtext r.to_html end end
