2011年11月14日月曜日

Railsを使ったアプリケーション開発 (その2 基礎編)


書籍を管理するアプリケーションを作ることを目的とする。

Railsを使ったアプリケーション開発 (その1 事前準備編)までは終わっているものとする。


コントローラの作成
これからはすべてbookappディレクトリ配下で作業を行う。
# cd /var/www/rails/bookapp

コントローラを作る。最初なのでコントローラ名はfirstとする。
複数のアクション(メソッド)をまとめたものがコントローラと考えていい。
# rails generate controller first
generateをdestroyにするとコントローラを破棄できる。

以下のファイルは既にできている。一部を修正するだけでよい。
# vi app/controllers/first_controller.rb
class FirstController < ApplicationController
  def index
    @msg = 'hello world!!'
  end
end



ビューの作成
# vi app/views/first/index.html.erb
<div id='main'>
<%= @msg -%>
</div>

ハイフン(-)を付与すると、後方のスペースや改行を除去できる。

<html>や<body>はレイアウト側で作られているため、
ビューのテンプレートに記載する必要はない。
ディフォルトのレイアウトとして次が使われる
# cat ./app/views/layouts/application.html.erb
<html>
<head>
(略)
<%= yield %> ← ここに埋め込まれる
(略)
</body>
</html>

レイアウトを変える場合はコントローラ内のアクションメソッドで指定する。
"app/views/layouts/layout.html.erb"が呼び出される。もちろん別テンプレートを使う場合は、自分で作成する必要がある。

def index
  render :layout => 'layout'
end



ルーティングの作成
:controllerと:actionはコントローラとその中のアクションメソッドであり、:idはアクションメソッドに渡されるパラメータである。丸括弧部分は省略可能である。
# vi config/routes.rb
get ':controller(/:action(/:id(.:format)))'

# rails routes



確認
http://x.x.x.x/first/index へブラウザからアクセスする。

hello world!!

と表示されれば成功である。

続いてモデルの開発を行うが、その前に備忘録。



備忘録
● ログについて
うまく表示されない場合はログを参考にエラー原因を特定する。
# tail -f log/development.log


● コントローラとビューについて
コントローラのアクションメソッドとビューのテンプレートを共に用意しなければならないのであろうか。

    コントローラのアクションメソッド ビューのテンプレート
(1) あり               あり
(2) なし               あり
(3) あり               なし

(1) 
これは上で作った通り、コントローラとビューを用意した場合である。リクエストの起点としてコントローラクラスのアクションメソッドが実行された後、対応するビューのテンプレートが検索され実行される。

(2)
アクションメソッドが存在しない場合、テンプレートファイルを直接見に行く。つまりビューだけでも問題ない。ただし、MVC(Model、View、Controller)は役割を分けることを目的としているため、意味もなくビューだけでアプリを完遂させるべきでないことは言うまでもない。

(3)
アクションメソッドが存在し、テンプレートファイルがない場合はエラーになる。ただし、次の場合を除く。

a. テキストスクリプトを出力する場合
# vi ./app/controllers/first_controller.rb
class FirstController < ApplicationController
  def index
    render :text => 'hello world!!'
  end
end


b. アクションメソッド内で、リダイレクトURIを指定している場合
# cat ./app/controllers/first_controller.rb
class FirstController < ApplicationController
  def index
    redirect_to 'http://example.com'   
  end
end


c. アクションメソッド内で、別のアクションメソッドを呼び出している場合
コントローラのアクションメソッドではなく、
ビューのテンプレートファイルが読み出されることに注意が必要である。

# vi ./app/controllers/first_controller.rb
class FirstController < ApplicationController
  def index
    @msg = 'hello world!!'
    render :action => 'index2'
  end
end


何度も言うが、actionとなっているが、ビューのテンプレートが読み出される。つまり、ビューのテンプレート"./app/views/first/index2.html.erb"が必要である。ディフォルトの"./app/views/first/index.html.erb"ビューテンプレートではなく、renderで指定したテンプレートを使う、とう意味である。renderの意味がレンダリングであることを考えれば混乱しないだろう。

ちなみに、HTMLの<form>タグではaction属性で、送信先プログラムのURIを指定できる。それは、普通にそのURIへの処理になる。あたりまえだが、Railsのアクションとは何も関係ない。

Rails的にはURIの処理過程で、コントローラのアクションメソッド、そしてビューのテンプレートファイルが読み出されるだけである。


● renderとは
renderの話が出たのでrenderの機能をまとめておく。描画するためのrendering処理であることを考えれば統一的な理解ができる。

render
・コントローラ内メソッドのからのビューのテンプレートの呼び出し
(1)の話である。

・コントローラ内メソッドでのテキストスクリプトの出力
(3)-a の話である

・ビューのテンプレートからの部分テンプレート呼び出し
ビューのテンプレートからでもrenderは使える。


● 部分テンプレートとは
部分テンプレートの話が出たのでそのことにも触れておく。
HTMLのヘッダやフッタとして使うテンプレートは異なるが、断片的な内容は同じである場合、コードを重複して書くことを避けるため、部分テンプレートを使う。

# vi ./app/views/first/index.html.erb
<div id='main'>
<%= render :partial => 'first/partial_form %>
</div>
:partialはなくてもよい

# vi ./app/views/first/_partial_form.html.erb
<div id='sub'>
<%= @msg %>
</div>

部分テンプレートファイル名の前につく'_'は必須である。これが部分テンプレートの宣言になる。



さて、話を戻そう。
モデルクラスの作成
モデルクラスを作成する。
SQLなどのデータベースでのリレーショナルモデルをアプリケーション側のオブジェクトモデルにO/R(Object/Relational)マッパーで橋渡しを行うことが目的である。

bookapp_developmentデータベースは既に作り終えている。

ある製品を管理するテーブルを作る。
実体属性は次とする。主キー属性に別色をつけている。

products
id name price sale

SQL的に表現すれば、products(製品群)テーブルにid、name(製品名)、price(価格)、sale(仕入れ日)のカラムがある。実際に製品を管理するには不十分な内容だが練習なのでこの程度でよしとしている。

では、モデルクラスを作る。
主キーとなるID、レコードの新規作成時用のcreated_at、レコードの更新日時のupdated_atは自動で作成されるためコマンド内に含める必要はない。

# rails generate model product name:string price:integer sale:date 

以下のファイルができる。
db/migrate/20111113031409_create_products.rb
app/models/product.rb
test/unit/product_test.rb
test/fixtures/products.yml


モデルとその関係ファイルを破棄する手順も残しておく。
# rails destroy model product



マイグレーションファイルによるテーブルの作成
"db/migrate/20111113031409_create_products.rb"というファイルを元にマイグレーションという機能を利用してテーブルを作成する。productsというテーブルができる。テーブル名が複数形なのは、テーブルの各行(モデルクラス的に表現すればオブジェクト)は
単数であり、テーブルはその集合だからである。複数形にするのはテーブルだけである。

# rails db:migrate RAILS_ENV=development
別のデータベースを使う場合はオプションを変更する。

RAILS_ENV=test
RAILS_ENV=production



テストデータの流し込み
テーブル内は空なので、"test/fixtures/products.yml"という自動で作成されるフィックスチャを元にテストデータを流し込んでおく。中を見ればわかるが2つの行(2つのオブジェクト)が投入される。流し入れるデータを変えたければymlファイルを編集すればよい。

# rails db:fixtures:load FIXTURES=products RAILS_ENV=development


フィックスチャ以外にも、シードファイルを使ってデータを入れることもできる。
# vi ./db/seeds.rb
Product.create(:name  => 'MyString3', :price => 3, :sale => '2011-11-11 09:00:00')

# rails db:seed



コントローラとビューの再作成
モデルも作ったのでそれを利用したコントローラとビューを作成する。
# vi app/controllers/first_controller.rb
class FirstController < ApplicationController
  def show
    @products = Product.all
  end
end


# vi app/views/first/show.html.erb
<table border="1">
  <tr>
    <th>NAME</th><th>PRICE</th><th>SALE</th>
  </tr>
<% @products.each do |product| %>
  <tr>
    <td><%= product.name %></td>
    <td><%= product.price %></td>
    <td><%= product.sale %></td>
  </tr>
<% end %>
</table>



サービス確認
ビューで定義したテーブルが表示できれば成功である。
http://x.x.x.x/first/show



Next ⇒ Railsを使ったアプリケーション開発 (その3 応用編)