生涯未熟

生涯未熟

プログラミングをちょこちょこと。

RailsによるアジャイルWEBアプリケーション開発第3版勉強!#3

前回は管理アプリケーションを色々と変更させてみました。
今回もどんどん変えていきましょう。


・入力情報の検査

フォームを通して入力されたデータが正しいかどうかのチェックをするように変更します。
変更するファイルはapp/models内にあるproduct.rbです。

class Product < ActiveRecord::Base
        validates_presence_of :title, :description, :image_url
        validates_numericality_of :price
        validate :price_must_be_at_least_a_cent
        validates_uniqueness_of :title
        validates_format_of :image_url,
                            :with       => %r{\.(gif|jpg|png)$}i,
                            :message    => 'はGIF、JPG、PNG画像のURLでなければな
りません'
        protected
                def price_must_be_at_least_a_cent
                        errors.add(:price, 'は最小でも0.01以上でなければなりませ
ん。') if price.nil? || price < 0.01
                end
end

最初はほとんど空のファイルでしたが色々追加されていますね。
順に上から見ていきましょう。

まずは、validates_presence_of :title, :description, :image_urlはtitle、description、image_urlが空かどうかをチェックしています。


validates_numericality_of :priceは、プライスのフォームに正の数以外が含まれているかどうかをチェックしています。


validate :price_must_be_at_least_a_centは、price_must_be_at_least_a_centというメソッドを追加しています。


validates_uniqueness_of :titleは、titleの値が他の商品と重複していないかどうかをチェックしています。


validates_format_of :image_url,〜は、正規表現を使いGIF、JPG、PNGかをチェックしています。

正規表現についてはこちらこちらをご参考に。


最後のprotectedから始まるメソッドは少し特殊で、protectedはオブジェクト指向をかじったことのある人には分かるかもしれませんがアクセスを制御するためのものでこのクラス内でのみ使用可能になる、というアクセス修飾子です。
そして、そのメソッドの内容はerrors.addを使いエラー内容を表示するのですが、その際if〜でfalseとなった時に表示というメソッドになっています。
ifの内容は、priceが空かどうかと0.01以下かどうかをチェックしています。


これでもしフォーム入力の際のミスが防げるようになりました。
実際に間違ってみた例が以下になります。




・見栄えをよくする

参考にしている本書では、顧客から商品リストの見栄えをもっと良くしてくれという名目で商品リストの改変を行います。
まず、目指すべき完成形はこちらです。

初期に比べたらかなり彩り良くなりました。
では、まず最初に専用のマイグレーションの作成から取り掛かりましょう。

>ruby script/generate migration add_test_data

次に、生成された○○_add_test_data.rbのファイルを改造します。

class AddTestData < ActiveRecord::Migration
  def self.up
    Product.delete_all

    Product.create(:title => 'Pragmatic Project Automation',
    :description =>
    %{<p>
       <em>Pragmatic Project Automation</em> shows you how to improve the 
       consistency and repeatability of your project's procedures using 
       automation to reduce risk and errors.
      </p>
      <p>
        Simply put, we're going to put this thing called a computer to work 
        for you doing the mundane (but important) project stuff. That means 
        you'll have more time and energy to do the really 
        exciting---and difficult---stuff, like writing quality code.
      </p>},
    :image_url =>   '/images/auto.jpg',
    :price => 29.95)


    Product.create(:title => 'Pragmatic Version Control',
      :description =>
      %{<p>
         This book is a recipe-based approach to using Subversion that will 
         get you up and running quickly---and correctly. All projects need
         version control: it's a foundational piece of any project's 
         infrastructure. Yet half of all project teams in the U.S. don't use
         any version control at all. Many others don't use it well, and end 
         up experiencing time-consuming problems.
      </p>},
    :image_url => '/images/svn.jpg',
    :price => 28.50)
    # . . .


    Product.create(:title => 'Pragmatic Unit Testing (C#)',
    :description =>
    %{<p>
        Pragmatic programmers use feedback to drive their development and 
        personal processes. The most valuable feedback you can get while 
        coding comes from unit testing.
      </p>
      <p>
        Without good tests in place, coding can become a frustrating game of 
        <br />"whack-a-mole." That's the carnival game where the player strikes at a 
       mechanical mole; it retreats and another mole pops up on the opposite side 
        of the field. The moles pop up and down so fast that you end up flailing 
        your mallet helplessly as the moles continue to pop up where you least 
        expect them.
      </p>},
    :image_url => '/images/utc.jpg',
    :price => 27.75)


  end

  def self.down
    Product.delete_all
  end
end

商品説明がとても長いです(- -;)
ここら辺は好みによって変えても大丈夫だと思います。
打つのが面倒くさい!って方は提供されている以下のプログラムをお使いください。

20080601000003_add_test_data.rb

%{・・・}の部分は、{}の中身を文字列としてリテラルしています。

そして、このマイグレーションを実行します。

>rake db:migrate

これでproductテーブルに上で記述したデータが読み込まれました。



データの設定は上記で出来ましたので、次に本題の外観を整える作業を行います。

今回はCSSを提供されているのでそれを使いましょう。
CSSサンプル

このCSSはdepotフォルダ内のpublicフォルダの中にあるstylesheetsフォルダに入れておいてください。
ファイル名はdepot.cssです。

次にこのCSSを使うためにhtmlファイルをいじっていきます。
app/views/layouts内にproducts.html.erbがありますのでまずはこれから。

<!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" xml:lang="en" lang="en">
<head>
  <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
  <title>Products: <%= controller.action_name %></title>
  <%= stylesheet_link_tag 'scaffold', 'depot' %>
</head>
<body>

<p style="color: green"><%= flash[:notice] %></p>

<%= yield  %>

</body>
</html>

8行目の <%= stylesheet_link_tag 'scaffold', 'depot' %> でdepot.cssを読み込んでいます。
この調子で関わりのあるHTMLファイルを変えていきましょう。
次はapp/views/productsフォルダにあるindex.html.erbファイルを変更します。

<div id="product-list">
<h1>商品一覧</h1>

<table>
<% for product in @products %>
  <tr class="<%= cycle('list-line-odd', 'list-line-even') %>">
        <td>
                <%= image_tag product.image_url, :class => 'list-image' %>
        </td>

        <td class="list-description">
                <dl>
                        <dt><%=h product.title %></dt>
                        <dd><%=h truncate(product.description.gsub(/<.*?>/,''),
                                :length => 80) %></dd>
                </dl>
        </td>

        <td class="list-actions">
                <%= link_to '表示', product %><br />
                <%= link_to '編集', edit_product_path(product) %><br />
                <%= link_to '破棄', product,
                                        :confirm => '本当に破棄してもよろしいで
すか?',
                                        :method => :delete %>
        </td>
  </tr>
 <% end %>
 </table>
</div>
<br />

<%= link_to '新しい商品', new_product_path %>

6行目ではcycleというヘルパーメソッドを使って、CSS内のlist-line-oddとlist-line-evenを交互に実行しています。
このように連続した行を交互に違うものを実行させるにはcycleが有効です。

14行目ではtruncateが使われていますが、これはlengthで決めた値分文字を表示させるようにしています。
そして、gsubはproduct.descriptionからHTMLタグを排除しているのです。

22行目のlink_toの部分では、:confirmというパラメータを使って破棄前の確認を実行しています。
そしてtrueならmethodでdeleteされます。


これでブラウザ上を確認すると綺麗な表示になっているかと思います。




今回はここまで。
次回は、カタログの作成を行います。