とりあえずトップページだけ作ってみます(その 1)。
閉鎖的な mixlone ではアカウントを持った人がログインした状態でないといかなるコンテンツも閲覧出来ないようにします。そのためには、
- mixlone の Controller 機能を集約する Main Controller の作成
- 認証情報(ひとの情報)を格納する Person Model の作成
- ログイン処理をする login Action の実装
- ログイン済みか確認しログインしていなければログインページへリダイレクトする before Filter の実装と設定
を実装しなければならないわけですが、今日は上記のうち 1 と 2 を実装します。
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 のこととかはとりあえず無視)。
- main_controller.rb が読み込まれます
- MainController のインスタンスが生成されます
- MainController の home メソッドが実行されます
- 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 を作成することにします。これは管理目的で使うもので利用者へは見せないということにします。
以下の通り 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.columnccupatioo, :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 のみでいくかもしれないけど…
とりあえず今日はここまで。
