mixi clone on rails 03

本日の目標

とりあえずトップページだけ作ってみます(その 1)。

閉鎖的な mixlone ではアカウントを持った人がログインした状態でないといかなるコンテンツも閲覧出来ないようにします。そのためには、

  1. mixlone の Controller 機能を集約する Main Controller の作成
  2. 認証情報(ひとの情報)を格納する Person Model の作成
  3. ログイン処理をする login Action の実装
  4. ログイン済みか確認しログインしていなければログインページへリダイレクトする before Filter の実装と設定

を実装しなければならないわけですが、今日は上記のうち 1 と 2 を実装します。

Main Controller の作成

Rails には Model や View/Controller のひな形を作成してくれる便利な script/generate というスクリプトが用意されています。

以下の通り script/generate を実行し Main Controller(と home Action と login Action) のひな形を作成します。

masakazu@debian:~/mixlone$ script/generate controller Main home login
exists  app/controllers/
exists  app/helpers/
create  app/views/main
exists  test/functional/
create  app/controllers/main_controller.rb
create  test/functional/main_controller_test.rb
create  app/helpers/main_helper.rb
create  app/views/main/home.rhtml
create  app/views/main/login.rhtml

app/controllers/main_controller.rb というのが Main Controller の本体です。なかみはこんな感じになっています。

FILE: app/controllers/main_controller.rb
1  class MainController < ApplicationController
2
3    def home
4    end
5
6    def login
7    end
8  end

app/views/main/home.rhtml と app/views/main/login.rhtml というファイルが作られていますが、これが View のテンプレートになります。なかみはこんな感じです(以下は home.rhtml ですが login.rhtml も基本的にいっしょです)。

FILE: app/views/main/home.rhtml
1  <h1>Main#home</h1>
2  <p>Find me in app/views/main/home.rhtml</p>

この状態で script/server -b 0.0.0.0 を実行し http://(サーバの IP アドレス):3000/main/home へアクセスすると以下の処理が実行されます(Helper Module のこととかはとりあえず無視)。

  1. main_controller.rb が読み込まれます
  2. MainController のインスタンスが生成されます
  3. MainController の home メソッドが実行されます
  4. home.rhtml をテンプレートとして HTML が生成されクライアントへ返されます

home.rhtml のひな形には static は HTML 文しか書かれていませんがここには <%= @variable %> のように変数を埋め込んだり <% 1.upto(10) do |i| %><%= “#{i}<br>” %><% end %> のように Ruby code も埋め込めます。ただし .rhtml ファイルに Ruby code が埋め込めるからといってロジックを .rhtml ファイルに書くようなことは避けるべきです。Controller 内の Action メソッドでロジックを実行し .rhtml ファイルはそれを埋め込むだけ、というスタイルにしておくのが良い習慣と言えます。View と Controller を分離することで、ロジックのことを考えるときはロジックのことだけに集中でき、見栄えのことを考えるときは見栄えのことだけに集中できるようになるからです。

Rails では Controller を複数作ることができます。本当であれば機能のまとまりごとに Controller を複数用意し Action を分離すべきなのかもしれませんが、 mixlon では、そんなに複雑にはならないであろうことと、第一めんどくさいので、 Main という Controller をひとつ用意してすべての Action を Main に集約することにします。

ただしこの次の Person Model の作成で scaffold を作りますが、 Model の scaffold に関しては Model::XxxController という名前の Controller を作成することにします。これは管理目的で使うもので利用者へは見せないということにします。

Person Model の作成

以下の通り script/generate で Person Model のテンプレートを作成します。

masakazu@debian:~/mixlone$ script/generate model Person
exists  app/models/
exists  test/unit/
exists  test/fixtures/
create  app/models/person.rb
create  test/unit/person_test.rb
create  test/fixtures/people.yml
create  db/migrate
create  db/migrate/001_create_people.rb

Person という名前の Model をつくっているのに最後の行で 001_create_people.rb というファイルが生成されていますが… Rails では Model のインスタンスを格納するデータベースのテーブル名は Model の“英語での”複数形にするという暗黙のルールが設けられています。このルールは必ず守らなければならないというわけではないですが、このルールに従っておくと Model とテーブルの対応付けを Rails が勝手にやってくれます。逆にルールを破るときは Rails に“この Model のテーブルは xxx ですよ”と教えてあげなければなりません。

app/models/person.rb というのが Person Model の本体です。なかみはこんな感じになってます。

FILE: app/models/person.rb
1  class Person < ActiveRecord::Base
2  end

ご覧の通り、 script/generate が生成する Model のひな形は Class の外枠があるだけです。

Person Model のインスタンスの保存先としてデータベースに people テーブルを作らなきゃならないわけですが、ふつうにデータベースに接続して CREATE TABLE … としてもいいんですが、 Rails には SQL 文をかかずに Ruby code だけでテーブルを作るための migration という機能があるので、使ってみます。

db/migrate/001_create_people.rb というファイルが生成されていますが、これを以下のように修正します(修正箇所を太字にしています)。

FILE: db/migrate/001_create_people.rb
1  class CreatePeople < ActiveRecord::Migration
2    def self.up
3      create_table :people do |t|
4        # t.column :name, :string
5        t.column :last_name, :string
6        t.column :first_name, :string
7        t.column :nickname, :string
8        t.column :password, :string
9        t.column :address_prefecture, :integer
10        t.column :address_city, :integer
11        t.column :sex, :integer
12        t.column :birth_year, :integer
13        t.column :birth_month, :integer
14        t.column :birth_day, :integer
15        t.column :blood_group, :integer
16        t.column :birthplace_prefecture, :integer
17        t.column :birthplace_city, :integer
18  #      t.column :hobies, :integer
19        t.column :o ccupatioo, :integer
20        t.column :belonging, :string
21        t.column :self_introduction, :text
22        t.column :favorite1, :integer
23        t.column :favorite2, :integer
24        t.column :favorite3, :integer
25      end
26    end
27
28    def self.down
29      drop_table :people
30    end
31  end

以下の通り rake db:migrate を実行すると 001_create_people.rb に書いた通り CREATE TABLE が実行されます。

masakazu@debian:~/mixlone$ rake db:migrate
(in /home/masakazu/mixlone)
== CreatePeople: migrating ====================================================
-- create_table(:people)
NOTICE:  CREATE TABLE will create implicit sequence "people_id_seq" for serial column "people.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "people_pkey" for table "people"
-> 0.0490s
== CreatePeople: migrated (0.0494s) ===========================================

ためしに psql で確認してみるとちゃんと people というテーブルが出来ています。

postgres@debian:~$ psql -d mixlone_development
Welcome to psql 8.1.9, the PostgreSQL interactive terminal.
Type:  \copyright for distribution terms
\h for help with SQL commands
\? for help with psql commands
\g or terminate with semicolon to execute query
\q to quit
mixlone_development=# \d
List of relations
Schema |     Name      |   Type   |  Owner
--------+---------------+----------+---------
public | people        | table    | mixlone
public | people_id_seq | sequence | mixlone
public | schema_info   | table    | mixlone
(3 rows)
mixlone_development=# \d people
Table "public.people"
Column         |          Type          |                      Modifiers
-----------------------+------------------------+-----------------------------------------------------
id                    | integer                | not null default nextval('people_id_seq'::regclass)
email_address         | character varying(255) |
password              | character varying(255) |
last_name             | character varying(255) |
first_name            | character varying(255) |
nickname              | character varying(255) |
address_prefecture    | integer                |
address_city          | integer                |
sex                   | integer                |
birth_year            | integer                |
birth_month           | integer                |
birth_day             | integer                |
blood_group           | integer                |
birthplace_prefecture | integer                |
birthplace_city       | integer                |
occupatioo            | integer                |
belonging             | character varying(255) |
self_introduction     | text                   |
favorite1             | integer                |
favorite2             | integer                |
favorite3             | integer                |
Indexes:
"people_pkey" PRIMARY KEY, btree (id)

people のほかに schema_info というテーブルができてますが、これは migration で管理するバージョン情報のようです。 migration 用のファイルは 001_create_people.rb のように数字 3 文字で始まるのですが、この 3 文字の数字が migration のバージョン番号になります。 migration を何個も作っていくとこの部分が 002, 003, … と増えていき rake db:migrate を実行するたびに schema_info の version よりも新しい migration 用のファイルが実行されていきます。 rake db:migrate には VERSION=xxx というオプションも指定でき、現在よりも古い状態まで戻すことが出来ます。そのときはすでに実行された migration 用ファイルの down クラスメソッドが逆順で実行されていきます。

Person Model も出来たしデータベースには people テーブルもできたのであとはひとの情報を入力していくわけですが、いちいち INSERT, UPDATE を実行していたのでは面倒です。Rails にはおなじみの scaffold という Model の情報を一覧表示したり新規追加したり削除したりするための View/Controller を用意してくれる機能があるのでこれを使って Person オブジェクトを管理するようにします。

以下の通り script/generate を実行します。

masakazu@debian:~/mixlone$ script/generate scaffold Person Model::Person
create  app/controllers/model
create  app/helpers/model
create  app/views/model/person
create  test/functional/model
dependency  model
exists    app/models/
exists    test/unit/
exists    test/fixtures/
identical    app/models/person.rb
identical    test/unit/person_test.rb
identical    test/fixtures/people.yml
create  app/views/model/person/_form.rhtml
create  app/views/model/person/list.rhtml
create  app/views/model/person/show.rhtml
create  app/views/model/person/new.rhtml
create  app/views/model/person/edit.rhtml
create  app/controllers/model/person_controller.rb
create  test/functional/model/person_controller_test.rb
create  app/helpers/model/person_helper.rb
create  app/views/layouts/person.rhtml
create  public/stylesheets/scaffold.css

上記では Person Model に対する scaffold を Model::Person という Controller に作成しています。

script/server -b 0.0.0.0 を実行し http://(サーバの IP アドレス):3000/model/person へアクセスするとこんな画面が表示されます。

New person をクリックすると新しい Person を登録するためのフォームが表示されるので適当に入力して自分のアカウントを作りましょう。アカウントとパスワードだけは直近で使う予定があるので空白だと困りますけど、それ以外はとりあえずは空白でもかまいません。追々 UNIQUE 制約とか NOT NULL 制約とかつけてきましょう。ひょっとしたら DB 側はそのままで Rails 側の Validation のみでいくかもしれないけど…

とりあえず今日はここまで。

Comments are closed.