FrontPage  Index  Search  Changes  Login

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 ボタンを押 すと(想定通り)以下のようなエラーになります。

Name can't be blank

それから、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 ディレクトリをコピーして きて配置すれば、以下のような画面になるはずです。

まだサイドメニューを作っていないのでその部分は空っぽですが、なかなかそ れらしくなってきたと思います。

Last modified:2005/11/27 11:20:37
Keyword(s):
References:[RailsでWikiクローンを作る]