目次

メールフォーム

概要

フォームに入力した内容をメールで送るプログラムです。webサイトのお問い合わせ受付画面などに利用できます。

パス

examples_controller

構成ファイル

ファイル名 説明
index.rb コントローラ使用のためのエントリポイント。
mailform/_contact.html お問い合わせ受付画面の部分テンプレート
mailform/_thanks.html お問い合わせを受付完了画面の部分テンプレート
mailform/layout.html 各画面共通のレイアウトを定義するための部分テンプレート
mailform/main.rb コントローラ
mailform/styles/ テンプレートから読み込む

使用ライブラリ

ライブラリ名 説明
al_controller コントローラクラス。コントローラアプローチで開発を行うために必要。
al_template テンプレートマネージャ。レスポンスとしてwebブラウザに送信するためのHTMLを生成します。
al_form フォームマネージャ。ブラウザから送信されたフォームデータの処理などを行います

詳細

コントローラ(hello/main.rb)でのフォームの処理

AlFormオブジェクトとAlWidgetオブジェクト

Aloneでフォームを表示したりクライアントから送信されたデータを受け取ったりするには、AlFormオブジェクトとAlWidgetオブジェクトを作成します。AlFormは一つのフォームに対応し、フォーム内のテキストボックスやセレクトボックスなどに対応するAlWidgetのサブクラスのオブジェクトを複数保持します。AloneではAlWidgetであらかじめ定義されたフォーム要素以外は受け取ることができません。これによりプログラマが想定していないデータを送り込まれることを防ぐことができ、セキュリティを高めることができます。

メールフォームサンプルでは、make_contact_formメソッドでこれらのオブジェクトを作成しています。

  def make_contact_form
    form = AlForm.new
    form.set_widgets(
      AlText.new('name', :label => 'お名前', :required => true, :tag_attr => {:size => 20}),
      AlMail.new('mail', :label => 'メールアドレス', :required => true, :tag_attr => {:size => 40}),
      AlText.new('company', :label => '会社・団体名', :required => false, :tag_attr => {:size => 40}),
      AlText.new('phone', :label => '電話番号', :required => false, :tag_attr => {:size => 14}),
      AlText.new('subject', :label => '件名', :required => true, :tag_attr => {:size => 40}),
      AlTextArea.new('message', :label => '内容', :required => true, :cols => 40, :rows => 8),
      AlSubmit.new('submit', :value => '問い合わせ送信')
    )
    return form
  end

フォームの表示

フォームを構成するHTMLをビューで生成するには、<form>タグの内側でAlForm#make_tagメソッドを呼び出して各ウィジェットに対応するタグを生成します。

コントローラのaction_indexメソッド内では、まずmain.rb内で定義されているmake_contact_formメソッドを呼び出してAlFormオブジェクトとAlwidgetオブジェクトを生成しています。

    @form = make_contact_form

その後、AlTemplate#runを呼び出し、ビューの処理を行っています。

    AlTemplate.run 'layout.html'

実際のフォームの生成は、layout.htmlから呼び出される部分テンプレート_contact.htmlが行っています。_contact.html内のフォーム関係部分を以下に示します。

  <form method="post" action="<%=h @form.action %>">
    <%=
    unless @form.validation_messages.empty?
    html = "<div style='color: red; font-weight: bold'><ul>"
        @form.validation_messages.each do |k, v|
        html << "<li>#{v}</li>"
        end
        html << "</ul></div>"
    end
    html
    %>
    <div>
      <label for="name">お名前:</label>
      <%= @form.make_tag(:name) %>
      <span class="description">例: 亜論 太郎</span>
    </div>
    <div>
      <label for="mail">メールアドレス:</label>
      <%= @form.make_tag(:mail) %>
      <span class="description">alone@example.com<br/>お問い合わせに対する回答を差し上げるメールアドレスです。</span>
  </div>
  <div>
    <label for="company">会社・団体名:<br/></label>
    <%= @form.make_tag(:company) %>
    <span class="description">例: イグザンプルコーポレーション<br/>差し支えなければご記入ください。</span>
  </div>
  <div>
    <label for="phone">電話番号:<br/></label>
    <%= @form.make_tag(:phone) %>
    <span class="description">例: 0853-00-0000<br/>差し支えなければご記入ください。</span>
  </div>
  <div>
    <label for="subject">件名:<br/></label>
    <%= @form.make_tag(:subject) %>
  </div>
  <div>
    <label for="message">内容:<br/></label>
    <%= @form.make_tag(:message) %>
  </div>
  <div align="center">
    <%= @form.make_tag(:submit) %>
  </div>
</form>

ウィジェットに対応するタグの生成

AlForm#make_tagメソッドをウィジェット名を表すシンボルをつけて呼び出すことにより、ウィジェットに対応するHTMLタグが表示されます。

エラーの表示

フォーム送信後、コントローラ内でAlForm#validationを実行した際にバリデーションエラーが発生した場合、メールフォームサンプルではエラーメッセージとともに再度フォームを表示します。エラーメッセージの表示は、バリデーションエラーのメッセージが格納される配列AlForm.validation_messagesが空でなければエラーメッセージのHTMLを生成することで実現しています。

GET/POSTメソッドでの処理分岐

本サンプルでは、1個のアクション action_index のみで、フォームの表示および送信されたフォームの処理(メール送信と受付画面の表示)を行っています。これは、HTTPメソッドがGETかPOSTかによって処理を分岐することにより実現しています。

HTTPメソッド種別の判別は、Alform#fetch_requestメソッドで行っています。fetch_requestメソッドは、HTTPリクエストに含まれるフォーム情報(POSTメソッドの場合)またはQUERY_STRING(GETメソッドの場合)を取得・解析します。本メソッドの引数に"POST"を指定して呼び出すとHTTPメソッドがPOSTでない場合はフォームの解析を行わずfalseを返すため、HTTPリクエストの判別に利用できます。

    if @form.fetch_request('POST') && @form.validate then
      @order_detail = mail_body(@form)
      send_mail(:from => MAIL_FROM, :to => RCPT_TO,
                :subject => MAIL_SUBJECT,
                :reply_to => @form.values[:mail], :body => @order_detail)
      @part_template = '_thanks.html'
    else
      @part_template = '_contact.html'
    end

フォーム要素の値の取得

フォームで送信された値を取得するにはAlForm#fetch_requestメソッドを使用します。このメソッドはフォームで送信された内容を解析し、AlFormオブジェクトにあらかじめ設定されていたAlWidgetオブジェクトに解析したフォーム要素の値をセットします。

なお、fetch_requestメソッドを呼び出した直後はウィジェット内部に値はセットされていますが、まだウィジェットから値を取り出すことはできません。値を取り出すためにはAlForm#validateメソッドを呼び出してバリデーションを行わなければなりません。値を使用する前にバリデーションが強制されることにより、プログラム内で参照できるフォームの値は妥当性検査を行ったものであることが保証され、プログラムのセキュリティが高まります。

AlForm#validateメソッドが呼び出されると、AlFormが保持しているすべてのAlWidgetオブジェクトに対してvalidateメソッドが呼び出されます。AlWidget#validateメソッドは各ウィジェットに組み込まれたデフォルトのバリデーションのほか、必須入力項目のチェック、:filter属性で指定されたバリデーションなどを行います。

メールフォームサンプルでAlForm#fetch_requestメソッドとAlForm#validateメソッドを呼び出しているコードを示します。通常、AlForm#fetch_requestとAlForm#validateは以下の例のように連続して呼び出します。

    if @form.fetch_request('POST') && @form.validate then

部分テンプレート

メールフォームサンプルでは、フォーム画面とフォーム送信後に表示される受付完了画面でレイアウトを共有するために、部分テンプレートを利用しています。部分テンプレートにより大半のHTMLを共有することができるため、重複した記述を排除してビューの記述量を減らしたりメンテナンスしやすくしたり等の効果が得られます。

両画面で共通して使われるlayout.htmlを示します。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta http-equiv="content-style-type" content="text/css" />
    <meta http-equiv="content-script-type" content="text/javascript" />
    <link rel="stylesheet" type="text/css" media="all" href="mailform/styles/css/common.css" />
    <link rel="stylesheet" type="text/css" media="all" href="mailform/styles/css/form.css" />
 
    <title>お問い合わせフォーム</title>
 
   </head>
   <body>
     <div class="header">
       <span id="site_title">お問い合わせ</span>
     </div>
 
     <div class="container">
 
       <div class="main">
         <% include @part_template %>
       </div>
 
     </div>
 
     <div class="footer">
       Copyright &copy;<%= Time.now.year %> Example Corporation.
     </div>
   </body>
 </html>

headタグ、ヘッダ表示部、フッタ表示など共通部分の記述はこのファイルで行っています。<% include @part_template %>を呼び出すことにより、インスタンス変数@part_templateに設定された部分テンプレートファイルを読み込みます。

インスタンス変数@part_templateはコントローラ内で設定されています。@part_templateを設定している箇所を示します。

    if @form.fetch_request('POST') && @form.validate then
      @order_detail = mail_body(@form)
      send_mail(:from => MAIL_FROM, :to => RCPT_TO,
                :subject => MAIL_SUBJECT,
                :reply_to => @form.values[:mail], :body => @order_detail)
      @part_template = '_thanks.html'
    else
      @part_template = '_contact.html'
    end