StoneDot の Ruby on Rails 講座

Railsで簡単掲示板その1

このページではRDBやSQLに対する簡単な理解があることを前提にしています。

ここから三回に渡ってRailsのアプリケーションを実際に作っていくことで、Railsの雰囲気を味わってもらおうと思います。

今回作るのは、2ch風掲示板です。なぜ、2ch風なのかというと、仕組み(構造)が簡単で、初めて作るには取っ付き易いからです。

掲示板の概要

実際に作り始める前にアプリケーションの概要を把握しておきましょう。まずは、どのようなページフローを想定するのか、データベースにはどのような物が必要そうかを紙などに書き出しておくと良いかと思います。

今回は下の図のような感じのものを書いてみました。 データベースの概略(仮) ページフローの概略(仮)

もちろん、このタイミングで完璧な仕様書を書くのは大変ですし、Railsはそんなことをしなくても十分に使えますので、大枠をつかむためにささっと作ってしまうのがコツです。頭の中に作るもののイメージがあると効率よく開発することが出来ます。

Railsアプリケーションの作成

念のため、Railsのバージョンを確認しておきましょう。以下のようなコマンドを実行すると

% rails --version
Rails 3.2.8
という感じでRailsのバージョンを確認できます。ここでは3.2系統のバージョンになっているかを確認しておいてください。

それでは、さっそくコーディングといきたいところですが、まずはRailsアプリケーション用のディレクトリを作る必要があります。

といっても難しくありません。コマンド一つですぐに作れます。「rails new」に続いて作りたいディレクトリ名を指定します。

rails new nch

上記のようなコマンドで nch という名前のディレクトリの中にRailsアプリケーション用のファイル群が作成されます。

今回は、ディレクトリ構造を深くは説明しませんが、皆さんが編集するであろうファイルはほとんど、 app ディレクトリに収められます。というのも、この app ディレクトリには貴方の作成するアプリケーションのControllerやView、Modelを入れることになるからです。

もし、途中でSQLite3関係のエラーで失敗する場合は、

sudo apt-get install libsqlite3-dev
等のコマンドを実行してsqlite3のライブラリをシステムにインストールしてみてから再度railsコマンドを実行してみてください。

データベースの作成

今回のアプリケーションにはデータベースとしてSQLite3を利用します。 SQLite3は軽量データベースで、Railsは標準でSQLite3をサポートしています。

実際にSQLite3をデータベースとして利用する場合は、config/database.ymlに以下のような記述を行います。標準の状態では以下のような記述がファイル内に見られるはずです。

development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000

もし、他のデータベースを使って開発したい場合はこの部分を編集します。

ところで、 developtment:test:production: のような記述が見られますが、これは開発時に使うデータベース、テスト時に使うデータベース、実稼働時に使うデータベースそれぞれの設定を記述するセクションを表しています。今回は development: の設定を確認していましたが、これが開発用のデータベースの設定に当たるわけです。

それでは実際にデータベースを作成してみましょう。データベースの作成は、

rake db:create
というコマンドで行うことができます。

これによって、 db/development.sqlite3 というファイルに開発用の、 db/test.sqlite3 というファイルにテスト用のデータベースが作成されます。

Hello, Rails!

それでは、実際にRailsアプリケーションを実行してみましょう。やり方はとっても簡単で、

rails server
だけで、OKです。ブラウザを立ち上げて、「http://localhost:3000/」にアクセスしてみましょう。このURLは自分自身(localhost)の3000番ポートにアクセスするという意味です。

うまくいくと、下のようなページが表示されるはずです。

Welocome aboard page

このページがうまく表示されれば、Railsアプリケーションがページを表示することができることを確認することができます。

サーバーを終了させたいときは、Ctrl+cをコンソール上で押下してください。

Topic モデルの作成

さて、先ほどのアプリケーションの概要で出てきた 2ch のスレッドに対応する Topic モデルを作ってみましょう。

Rails ではデータベースの管理のためにデータベースマイグレーションというものを定義して、データベースに変更を適用していきます。マイグレーションを適用すれば、データベースが新しいスキーマに更新され、ロールバックすればデータベースを元のスキーマに戻すこともできます。

ここでは、マイグレーションをあまり意識しないで済む方法を使っていきます。しかし、後からマイグレーションを本格的に使いたくなった時にも困らない最も適切な方法です。

topics テーブルを作成するためのマイグレーションを生成し Topic というモデルオブジェクトを生成するには、以下のようなコマンドを利用します。

rails generate scaffold Topic title:string
このコマンドで、文字列を格納できる title カラムを持つ topics テーブルを作成するマイグレーションを生成できます。

それに加えて、このオブジェクトを編集、表示するためのページや、 Model オブジェクトなども一括で生成してくれます。

ところで、なぜモデルオブジェクトの名前は大文字で始まる Topic で、データベースのテーブル名は topics と小文字で始まる複数形になっているのかと疑問に思うのかもしれません。

これが、 Rails の哲学の一つの「設定より規約」の現れです。 Ruby ではクラス名を大文字で始まる単数にするという慣習があるので、 モデルオブジェクトは Topic となります。データベースには複数の topic を格納するので、 topics という形になっています。また、データベースのテーブル名をすべて小文字にするのは一般的なことです。

それでは、データベースにマイグレーションを適用してみましょう。マイグレーションを適用するコマンドは以下の通りです。

rake db:migrate

これで、データベースにマイグレーションが適用されて、 topics テーブルが作成されます。

実際にうまくいっているか確かめてみましょう。サーバーを起動して、「http://localhost:3000/topics/」にアクセスしてみましょう。

Title: Listing topics

上記のような画面が表示されれば成功です。この状態でも、既に Topic の作成ができることを確かめてください。

マイグレーションの確認

マイグレーションについて本格的な説明は後にして、どのようなマイグレーションファイルが生成されているのか確認しておきましょう。

マイグレーションのプログラムは db/migrate/20121206000207_create_topics.rb に書かれています。ファイルの前についている数字はマイグレーションが生成された日時をもとにしているので、各自の環境で若干違うであろう点に注意してください。

class CreateTopics < ActiveRecord::Migration
  def change
    create_table :topics do |t|
      t.string :title

      t.timestamps
    end
  end
end

ファイルの中身は上記のようになっているはずです。

change メソッドはマイグレーションを実行する際に呼ばれるメソッドで、ここにデータベース変更のためのコードを追加していきます。

同様に reverse メソッドを定義することもできます。 reverse メソッドを定義した場合は、 rake コマンドを利用してマイグレーションでなされた変更を元に戻すことが出来ます。ただし、その処理を明示的に書かなければいけません。

気を付けたいのが scaffold の時に指定していなかったタイムスタンプに関する記述が追加されていることです。

Rails はデフォルトでタイムスタンプ用のカラムを自動に生成し管理までしてくれるので、データを生成する際にこのタイムスタンプについて明示的に考える必要はありません。

ルーティングの変更

私たちの製作するアプリケーションの最初の画面は、このスレッドを選択する画面でした。なので、「http://localhost:3030/」にアクセスしたときに、先ほどのページが表示されるようにしてみましょう。

まずは、 config/routes.rbの中のコメントアウトされている、以下の記述を探します。

# root :to => 'welcome#index'

これが、パスに / が指定された場合に利用されるアクションを表します。アクションはリクエストに対する具体的な処理を記述するメソッドのことで、それそれぞれのコントローラの中に記述されているメソッドのうち公開されているものはすべてアクションとして扱われます。この部分を以下のように変更することで、topics コントローラーの index アクションに / が指定された際の処理を委任することができるようになります。

root :to => 'topics#index'

ただし、これだけではこの機能は有効になりません。 public/index.html を削除しましょう。

rm public/index.html

これで、「http://localhost:3000/」にアクセスしたときに 「Listing topics」が表示されるようになるはずです。

コントローラの確認

先ほどコントローラの話が出てきたので、実際にどのようなものなのか見てみましょう。 topics コントローラーは app/controllers/topics_controller.rb です。基本的に、コントローラーは app/controllers/ ディレクトリに保存されます。

class TopicsController < ApplicationController
  # GET /topics
  # GET /topics.json
  def index
    @topics = Topic.all

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @topics }
    end
  end

  # GET /topics/1
  # GET /topics/1.json
  def show
    @topic = Topic.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @topic }
    end
  end

  # GET /topics/new
  # GET /topics/new.json
  def new
    @topic = Topic.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @topic }
    end
  end

  # GET /topics/1/edit
  def edit
    @topic = Topic.find(params[:id])
  end

  # POST /topics
  # POST /topics.json
  def create
    @topic = Topic.new(params[:topic])

    respond_to do |format|
      if @topic.save
        format.html { redirect_to @topic, notice: 'Topic was successfully created.' }
        format.json { render json: @topic, status: :created, location: @topic }
      else
        format.html { render action: "new" }
        format.json { render json: @topic.errors, status: :unprocessable_entity }
      end
    end
  end

  # PUT /topics/1
  # PUT /topics/1.json
  def update
    @topic = Topic.find(params[:id])

    respond_to do |format|
      if @topic.update_attributes(params[:topic])
        format.html { redirect_to @topic, notice: 'Topic was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @topic.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /topics/1
  # DELETE /topics/1.json
  def destroy
    @topic = Topic.find(params[:id])
    @topic.destroy

    respond_to do |format|
      format.html { redirect_to topics_url }
      format.json { head :no_content }
    end
  end
end

上記のようなファイルになっているはずです。

TopicsController のように、コントローラーの名前はデータベース名の最初の文字を大文字にしたものに Controlloer を追加したものになります。

TopicsController の各メソッドはパスと HTTP メソッドに対して以下の対応関係を持っています。

{id} というのは Topic オブジェクトを識別する一意の番号で、Railsによって自動的に付加されます。

このように Controller に定義されたメソッドはパスとHTTPメソッドに一対一に対応しています。

この各アクションメソッドの内容を変更していくことで、アプリケーションの動作を作っていくことになります。

モデルの確認

つぎに Topic モデルの確認を行います。モデルは app/models 内にあります。今回は Topic モデルの app/models/topic.rb を開いてみましょう。