Rails 2.0.2でサンプルアプリ

ちょっとましなサンプルを2.0.2の作法で作ってみることにする。
参考:http://www.kestrel.jp/modules/tinyd04//content/index.php?id=1

上記URLを参考に、rails2.0流に。

1.ベースの作成

適当なところで、いつものベースの作成

$ rails rails_2.0-sample
      create
      create  app/controllers
      create  app/helpers
      create  app/models
      create  app/views/layouts
      create  config/environments
      create  config/initializers
・・・
$ cd rails_2.0-sample

2.足場(scaffold)の作成

今回、Person と Person の属する Organazation の二つのモデルを使います。rganazation は名前(name)を持ち、Person は名前(name)と所属するOrganazationのid(orgId)をもちます。それぞれ scaffoldを作成します。

$ ruby script/generate scaffold Organization name:string
      exists  app/models/
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/organizations
      exists  app/views/layouts/
・・・
$ ruby script/generate scaffold Person name:string orgId:integer
      exists  app/models/
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/people
      exists  app/views/layouts/
・・・

scaffold作成の引数に、それぞれ持っている属性を指定します。なお、Person は人の単数形で、テーブル名は自動的に複数形のPeopleに変換されています。
migrateファイルもそれに合わせて自動的に生成されるので、rakeでデータベースへ反映します。

$ rake db:migrate
(in /xxx/xxx/rails_2.0-sample)
== 1 CreateOrganizations: migrating ===========================================
-- create_table(:organizations)
   -> 0.0038s
== 1 CreateOrganizations: migrated (0.0039s) ==================================

== 2 CreatePeople: migrating ==================================================
-- create_table(:people)
   -> 0.0037s
== 2 CreatePeople: migrated (0.0039s) =========================================

3.データベースの確認

一応、sqliteで確認。

$ sqlite3 db/development.sqlite3
SQLite version 3.5.2
Enter ".help" for instructions
sqlite> .schema
 CREATE TABLE organizations (
  "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
  "name" varchar(255) DEFAULT NULL,
  "created_at" datetime DEFAULT NULL,
  "updated_at" datetime DEFAULT NULL);
 CREATE TABLE people (
  "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
  "name" varchar(255) DEFAULT NULL,
  "orgId" integer DEFAULT NULL,
  "created_at" datetime DEFAULT NULL,
  "updated_at" datetime DEFAULT NULL);
CREATE TABLE schema_info (version integer);
sqlite>.q

4.サーバ起動と確認

以上で基本的な設定は終了。サーバーを起動して動作確認。

$ ./script/server
=> Booting WEBrick...
=> Rails application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options

http://HOSTNAME:3000/organizationhttp://HOSTNAME:3000/people にアクセスするとそれぞれ、組織、人のリストが見れます。

4.表示カラムの追加

peopleの一覧画面をみると、Name と Organization だけ表示されています。ここに、IDと作成日時、更新日時も表示するように修正してみる。app/views/people/index.html.erb を編集する。

<h1>Listing people</h1>

<table>
  <tr>
    <th>id</th>           <!-- ← 追加  -->
    <th>Name</th>
    <th>Orgid</th>
    <th>作成日時</th>     <!-- ← 追加  -->
    <th>更新日時</th>     <!-- ← 追加  -->
  </tr>

<% for person in @people %>
  <tr>
    <td><%=h person.id %></td>           <!-- ← 追加  -->
    <td><%=h person.name %></td>
    <td><%=h person.orgId %></td>
    <td><%=h person.created_at %></td>   <!-- ← 追加  -->
    <td><%=h person.updated_at %></td>   <!-- ← 追加  -->
    <td><%= link_to 'Show', person %></td>
    <td><%= link_to 'Edit', edit_person_path(person) %></td>
    <td><%= link_to 'Destroy', person, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>
</table>

<br />

<%= link_to 'New person', new_person_path %>

これで、再度 peopleのリスト画面を見ると、ID、作成日時、更新日時が表示される。特にサーバの再起動は必要ない。

5.テーブルの結合

people と organization テーブルを結合して、people を表示するときに、orgIdではなく、組織名を表示するようにしてみる。また、新規作成時に所属をidではなく、選択から選べるようにもする。

まず、Person と Organization との関係をモデルに定義する。Person と Organization は 多対1なので、Personモデルに、Organization に所属している belongs_to を定義する。このとき、外部キーとして orgId を使うことを定義。(organization_id とかいうカラム名だったら明示なので不要??)

["app/models/person.rb"]
class Person < ActiveRecord::Base
  belongs_to :organization, :foreign_key => "orgId"
end

Organization のほうに Person を持ってるよという、has_many を定義してもよいが、今回は使わないのでパス。とりあえず、これで、person.organization.name で関連する組織名をとってこれるようになった。
次は、表示部分の変更。app/views/people/index.html.erb を以下のように変更。

<h1>Listing people</h1>

<table>
  <tr>
    <th>id</th>
    <th>Name</th>
    <th>組織</th>              <!-- ← 修正 -->
    <th>作成日時</th>
    <th>更新日時</th>
  </tr>

<% for person in @people %>
  <tr>
    <td><%=h person.id %></td>
    <td><%=h person.name %></td>
    <td><%=h person.organization.name %></td>   <!-- ← 修正 -->
    <td><%=h person.created_at %></td>
    <td><%=h person.updated_at %></td>
    <td><%= link_to 'Show', person %></td>
    <td><%= link_to 'Edit', edit_person_path(person) %></td>
    <td><%= link_to 'Destroy', person, :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>
</table>

<br />

orgIdを表示していたところを、ヘッダを「組織名」、値を person.organization.name を表示するように修正。これで、関連する組織名が表示されます。

次は、新規追加時に組織名を選択できるように修正。
app/views/people/new.html.erb を変更。

<h1>New person</h1>

<%= error_messages_for :person %>

<% form_for(@person) do |f| %>
  <p>
    <b>Name</b><br />
    <%= f.text_field :name %>
  </p>

  <p>
    <b>Orgid</b><br />
    <!-- 以下を追加 -->
    <%= select("person", "orgId", Organization.find(:all).collect {|e| [ e.name, e.id ] }) %>
  </p>

  <p>
    <%= f.submit "Create" %>
  </p>
<% end %>

<%= link_to 'Back', people_path %>

<%= f.text_field :orgId %> とかあるところを削除して、上記の例の1文に書き換える。同様の修正を app/views/organizations/edit.html.erb に行えば完了。
Webブラウザからアクセスして、新規追加をするときに 組織名を選択できるようになる。