minimize

事業拡大のため、新しい仲間を募集しています。
→詳しくはこちら

さて、今度はモデルを作ってみる。

generate scaffold

% script/generate scaffold Post name:string title:string content:text
      exists  app/models/
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/posts
      exists  app/views/layouts/
      exists  test/functional/
      exists  test/unit/
      exists  public/stylesheets/
      create  app/views/posts/index.html.erb
      create  app/views/posts/show.html.erb
      create  app/views/posts/new.html.erb
      create  app/views/posts/edit.html.erb
      create  app/views/layouts/posts.html.erb
      create  public/stylesheets/scaffold.css
      create  app/controllers/posts_controller.rb
      create  test/functional/posts_controller_test.rb
      create  app/helpers/posts_helper.rb
       route  map.resources :posts
  dependency  model
      exists    app/models/
      exists    test/unit/
      exists    test/fixtures/
      create    app/models/post.rb
      create    test/unit/post_test.rb
      create    test/fixtures/posts.yml
      create    db/migrate
      create    db/migrate/20090315021022_create_posts.rb

なんか大量に作成された。scaffold とは訳すと「足場」。
モデルの意味だろうか。今回はPostモデルを作成した。
これでPostを扱う一連のページが作成されたことになる。

モデルとは Java Bean のようなものだ。
まぁここら辺は他のMVCと変わらない。
今回のPostは name, title, context の3要素を持つ。

とりあえず、作られたファイルの簡単な説明が以下。

post.rb Postモデル。ActiveRecord::Base を継承するPostクラスを定義する。
YYYYMMDDHHMMSS_create_posts.rb CREATE TABLE文。ファイル名に日付が付いているのには意味がある
app/views/posts/XXX.erb 各ERBファイル。これがViewとなる。
app/views/layouts/posts.html.erb 上で定義した各Viewの親となるView。ここに各Viewが埋め込まれる形になる
scaffold.css その名の通り、スタイルシート
posts_controller.rb メインとなる処理。ApplicationController を継承する PostsController クラスを定義する。
posts_helper.rb Postsのヘルパー。詳しくはまだ不明
config/routes.rb 前に説明したURLマッピング定義ファイル。ここに1文追加される
test/XXX 各種テストケース

db:migrate

さて、ここからRailsの本領発揮。
Railsはデータベース定義もコード同様に保守していく。
そしてテーブル定義の自動生成はもちろん、いつでも過去の状態に戻せる。
コードだけ過去の状態に戻しても、テーブル定義が新しいままで
プログラムが動かないなんて経験はよくあるだろう。
Railsではデータベースもコードの一部。
この考え自体は昔から僕が思ってたことだが、それをこうやって実践できるところがすごい。

% rake db:migrate
(in /mnt/var/prog/rails/sample2)
==  CreatePosts: migrating ====================================================
-- create_table(:posts)
   -> 0.0038s
==  CreatePosts: migrated (0.0046s) ===========================================

これで、テーブルが作成された。

db1.png

このように。
Railsのテーブルは必ずidカラムを持ち、これがPrimary Keyになる。
他に、schema_migrations というテーブルも作成される。
これでテーブル定義の履歴を管理する。

link_to

一通り準備は揃った。
トップページに、今作成したページへのリンクを張ってみよう。

/app/views/home/index.html.erb

<h1>Hello, Rails!</h1>
<%= link_to "My Blog", posts_path %>

2行目の <%= %> で囲まれた部分が、erbで埋め込んだRubyコード。
link_to というのが、リンク(Aタグ)を作るメソッドだろう。
第一引数が表示文字列、第二引数が遷移先。
ちなみにこの posts_path という変数、見たところどこでも定義されていない。
とりあえず、これが "/posts" に展開される。この謎はいずれ解明しよう。

posts/index

posts_index.png

これがpostsのindexページ。
少しViewファイルを見てみよう。

app/views/posts/index.html.erb

<h1>Listing posts</h1>

<table>
  <tr>
    <th>Name</th>
    <th>Title</th>
    <th>Content</th>
  </tr>

<% for post in @posts %>
  <tr>
    <td><%=h post.name %></td>
    <td><%=h post.title %></td>
    <td><%=h post.content %></td>
    <td><%= link_to 'Show', post %></td>
    <td><%= link_to 'Edit', edit_post_path(post) %></td>
    <td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>
</table>

<br />

<%= link_to 'New post', new_post_path %>

そんなに難しいことはやっていない。
@posts に、おそらくDBから取得したPost一覧が入るのだろう。
今はまだ何も投稿していないので、for ~ end の部分はスルーされる。
この中身は後で見ていくことにする。

最後に link_to。
ここの new_post_path が、"posts/new" に展開される。
まだこの部分が謎だが、何らかのルールに従ってるはずなので
いずれそのルールを解明しよう。

PostsController.index

先にViewを見てしまったが、Controller の方も見ておこう。

app/controllers/posts_controller.rb

def index
  @posts = Post.find(:all)
  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @posts }
  end
end

予想した通り、@posts にはPost一覧を取得していた。
@ で始まる変数は、Javaでいうところのフィールド。インスタンス変数である。
あとは画面表示だけ。xmlでも表示できるらしいが、その部分はまた後にしよう。