RailsでWikiクローンを作る03
ページ新規作成画面の実装
入力フォームの生成
ジェネレータで生成された雛形を元に、Minki の個々の機能の実装を始めます。 まずは「ページの新規作成」です。
「ページの新規作成」のアクションは、wikiコントローラに new という名前 で作ることにします。 new のやるべきことは、新規ページ名の入力を求める フォームを表示することです。表示はビューの担当ですので、new アクション は今のところ何もしないままで放置します (ジェネレータが生成した空の定義 のまま)。
一方、対応するビューのテンプレート app/views/wiki/new.rhtml は以下のよ うに書き換えます。
<h1>新規作成</h1> <%= start_form_tag :action => 'create' %> <%= text_field 'page', 'name' %> <%= submit_tag "Create" %> <%= end_form_tag %>
そしてhttp://localhost:3000/wiki/newにアクセスします。

Railsでは、フォームはヘルパーメソッドと呼ばれる Rails が用意しているメ ソッド群を使って作ります。直接、フォームの HTMLタグを書くことは避ける べきです。ヘルパーメソッドを使うことで、パラメータの受け渡しが簡単に処 理できたり、後で出てくるバリデーション機構が使いやすくなります。
フォームの開始と終了のタグは、それぞれ start_form_tag と end_form_tag で生成します。 start_form_tag の引数 :action => 'create' でフォームの submit ボタンが押されたときに実行されるアクションを指定しています (createアクションはまだ作っていません)。
テキストフィールドのタグは text_field で生成します。 Railsのフォーム関 連の機能は、モデルの存在を前提としたものになっていて、上記の例の text_field 'page', 'name'は、page というモデルの name というカラムに格 納されるべき値というような意味になります。ちなみにこの部分は、通常時は
<input id="page_name" name="page[name]" size="30" type="text" />
という HTML に展開されます。
submit ボタンは submit_tag で生成します。 submit が押されると、ユーザ によってテキストフィールドに入力された値がパラメータとして start_form_tag の :action で指定したアクション(ここではcreate)に渡され ます。
パラメータの受取り
では次に、その create アクションを作ります (create は、直接対応するビュー を持たないアクションです)。 app/controllers/wiki_controller.rb の create メソッドを以下のように書き換えます。
def create
@page = Page.new(params[:page])
if @page.save
redirect_to :action => 'edit', :id => @page.name
else
render :action => 'new'
end
end
アクションが呼び出されるときのパラメータは、Rails では params という属 性で参照することができるようになっています。
例えば、先ほどの new アクションのビューの中で、text_field 'page', 'name'と書いたテキストフィールドの入力値は、params[:page] の :name と いうキーで得ることができます。 つまり、params の :page というキーで示 される値 params[:page](ハッシュ)が page モデル関連の入力パラメータになっ ていて、その値は {:name => 入力値} というハッシュです。 この形式は、そ のまま Page.new の渡せる形になっていますので、結局 @page = Page.new(params[:page])と書くことによって、 new アクションで入力された 値を元に、モデルの新しいレコードを生成することになります。この書き方は、 入力フォームで入力された値に基づき、DBテーブルに新しい行を追加する場合 の常套句です。
なお、この時点では新しいレコードが Ruby 上で生成されただけで、まだ DB には一切書き込んでいません。 DBに書き込むには、save メソッドで行います。 save は書き込みに成功したか否かを真偽値で返すので、if @page.saveで書き 込みと同時に成否を判断し、成功したら新規ページを編集するために edit ア クション(後で実装)へリダイレクトし、失敗したら new の画面に戻すことに なります。
Railsでは、他のアクションのURLへリダイレクトするには、redirect_to とい うヘルパーメソッドを使います。:action => 'edit' でアクション名を指定し、: id => @page.name でIDを指定します。
save でエラーが起きた場合は、もう一度新規入力画面に戻したいわけなので、 render というヘルパーメソッドを使って、'new' アクションのビューを表示 します (create には、もともと対応するビューはありませんが、あったとし ても render :action => アクション名という文があると、指定したアクショ ン名のビューが使われることになります)。
バリデーション(入力値正当性検査)
Rails では、モデルを通じて DB に値を保存する前に、その値が本来とるべき 値かどうかを検査する仕組みがあります。その検査のことをバリデーションと 言います。
例えば、ページの新規作成画面でページ名に何も入力しなかったら、はじくよ うにしなければなりませんが、その場合はモデルクラスの定義 (app/models/page.rb)に以下のように書きます。
class Page < ActiveRecord::Base validates_presence_of :name end
これで、Page の name 要素が空っぽな場合にエラー(Page#saveがfalseを返す) となります。
エラーの情報はビュー側で利用することができます。 app/views/wiki/new.rhtml を以下のように変更します。
<h1>新規作成</h1> <%= error_messages_for 'page' %> <%= start_form_tag :action => 'create' %> <%= text_field 'page', 'name' %> <%= submit_tag "Create" %> <%= end_form_tag %>
<%= error_messages_for 'page' %> という行を追加しています。 error_messages_for は引数にインスタンス変数名(ここでは@page)をしていま す。これで、エラーがあった場合はそのエラーが表示されるようになります。
なお、error_messages_for が @page を必要とするため、newアクションでも @pageをビューに渡すようにしなければなりません。よって、 app/controllers/wiki_controller.rb の new メソッドを以下のように書き換 えます。
def new @page = Page.new end
これで、ページの新規作成画面で、ページ名を入力せずに Create ボタンを押 すと(想定通り)以下のようなエラーになります。

それから、HTMLのソースをみるとわかりますが、エラー時に text_field の部分は以下のように div タグで囲まれるようになります(実際は一行)。
<div class="fieldWithErrors"> <input id="page_name" name="page[name]" size="30" type="text" value="" /> </div>
スタイルシートで fieldWithErrors というクラスを適切に設定してやれば、 エラーが起こった入力フォームを目立たせることができます。例えば scaffold では背景を真っ赤にするスタイルシートが生成されます。
layout
今後、ビューのテンプレートをいくつか作っていくわけですが、ページのヘッ ダ、フッタ、サイドバーなど、多くのビューで共通する部分があります。これ をそれぞれのテンプレートに重複して記述していては DRY 精神に反するので、 その共通部分をまとめて管理するための layout という仕組みがあります。
layoutの仕組みを利用するには、決まった場所にレイアウト用テンプレートファ イルを置くだけです。決まった場所とは、コントローラの名前から、規約によっ て自動的に決められる場所で、 wiki コントローラのレイアウト用ファイルの 置き場は app/views/layouts/wiki.rhtml です。ここでは、以下のような内容 の wiki.rhtml を作ります。
<html> <head> <title>Minki: <%= @title %></title> <%= stylesheet_link_tag '/theme/hiki/hiki.css' %> </head> <body> <a name="top"></a> <div class="main"> <h1 class="header"><%= @title %></h1> <div class="day"> <%= @content_for_layout %> </div> </div> <div class="sidebar"> </div> </body> </html>
stylesheet_link_tag は、スタイルシートのタグを生成するヘルパーメソッド です。ここではとりあえず決め打ちでパスを書いています。
インスタンス変数 @content_for_layout には各ビューのテンプレートで生成 された内容が入っています。よって <%= @content_for_layout %> の部分は各 ビューの内容で置き換えられることになります。
一方、ビューのテンプレート app/views/wiki/new.rhtml も、layout の利用 にあたってちょっとだけ手直しをします。
<% @title = '新規作成' %> <div class="body"> <%= error_messages_for 'page' %> <%= start_form_tag :action => 'create' %> <%= text_field 'page', 'name' %> <%= submit_tag "Create" %> <%= end_form_tag %> </div>
layoutファイル wiki.rhtml 内で使用するインスタンス変数 @title の値をセッ トして、h1タグの生成を wiki.rhtml 側にまかせるようにし、あと tDiary の テーマを利用するために div タグを追加しました。

あとは、public ディレクトリに Hiki から theme ディレクトリをコピーして きて配置すれば、以下のような画面になるはずです。
まだサイドメニューを作っていないのでその部分は空っぽですが、なかなかそ れらしくなってきたと思います。

Keyword(s):
References:[RailsでWikiクローンを作る]