掲示板っぽくする

さて、これではちょっと掲示板とはいえない。
色々直さなければいけないところがあるので、変更すべき点を挙げてみる。

  1. 記事投稿の際、時間は指定できては困る
  2. 記事は日付順で新しいものが上にくるようにしたい
  3. 見た目がまるで掲示板ではないので、掲示板ぽいスタイルにする
  4. 入力必須項目をつくりたい(バリデーション)
  5. 誰でも投稿できるのはよいが、編集・削除はできないようにしたい

日付を自動で入れるようにする

まずは、記事の投稿時に日付を手動で入力できてしまう点が、
掲示板としては明らかにおかしいので、この点を直そうと思う。

と、ここでRailsのConvention over Configurationが威力を発揮する。

先ほどつくったデータ構造

  • id(記事番号)
  • date(日時)
  • name(投稿者の名前)
  • title(タイトル)
  • body(本文)

今回厄介なのはこのうちの「日時」をあらわす「date」カラム。
一般的なウェブアプリケーション開発の感覚からいくと、
このように手動で「date」カラムを用意してプログラム側でそこに現在時刻を代入するんだろう
と思いきや、Ruby on Railsには「updated_at」というマジックカラムというものが存在する。

これこそが「規約」で、「updated_at」というカラムをテーブルに追加しておくと、
自動的にそこにそのレコードの更新時刻が登録されるようなのである。

ということで、データベースのdateカラムをupdated_onに書き換える。

ALTER TABLE `articles` CHANGE `date` `updated_at` DATETIME NOT NULL 

ちなみに、updated_atなのでご注意。

ついでに、データ構造が変わってしまったので、一旦サーバーを終了してもう一回scaffoldを実行する。
(ほんとはあまりこんなことはしないほうがよいらしいが、まあ初回なので)

ruby script/generate scaffold Article

すると、いくつかファイルを上書きするかたずねられるので、Yesとしておく。

日付の入力欄を削除する

さて、この状態でもう一回サーバーを起動してページにアクセスしてみると、
相変わらず日付の入力欄がある。

ので、今度はビューのファイルをいじってこの日付入力欄を消してしまおう。

app/views/articles/_form.rhtml
がフォーム関連のHTMLテンプレートが書いてあるファイル。

このうち、日付入力部分にあたる

<p><label for="article_updated_at">Updated at</label><br/>
<%= datetime_select 'article', 'updated_at'  %></p>

を丸ごと消去してしまえばよい。

この状態で記事の投稿を行うと、自動的にUpdated_atには記事の編集時刻が入るようになっている。

ここまで、書いたソースコードの行:0行。

新しい記事が上に来るようにする

掲示板たるもの、新着記事が一番最初に表示されないようでは使い勝手が悪すぎる。
ということで、新着記事が一番上に表示されるようにしたい。

ここの部分を変えるにはコントローラをいじる必要がある。

Railsアプリケーションのコントローラはapp/controllersディレクトリにあるが、
ここではscaffoldによって生成されたarticles_controller.rbを開く。

class ArticlesController < ApplicationController
  def index
    list
    render :action => 'list'
  end

  # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
  verify :method => :post, :only => [ :destroy, :create, :update ],
         :redirect_to => { :action => :list }

  def list
    @article_pages, @articles = paginate :articles, :per_page => 10
  end

  def show
    @article = Article.find(params[:id])
  end

  def new
    @article = Article.new
  end

  def create
    @article = Article.new(params[:article])
    if @article.save
      flash[:notice] = 'Article was successfully created.'
      redirect_to :action => 'list'
    else
      render :action => 'new'
    end
  end

  def edit
    @article = Article.find(params[:id])
  end

  def update
    @article = Article.find(params[:id])
    if @article.update_attributes(params[:article])
      flash[:notice] = 'Article was successfully updated.'
      redirect_to :action => 'show', :id => @article
    else
      render :action => 'edit'
    end
  end

  def destroy
    Article.find(params[:id]).destroy
    redirect_to :action => 'list'
  end
end

ここの部分の理解には若干Ruby自体の文法の理解が必要だが、
ひとまずC言語Javaと大きく異なるのは、ブロックが{}ではなくclassやdef〜endで記述されている点。

このファイルの場合はArticlesControllerというクラスの中に
index,list,show,new,create,edit...等のメソッドが定義されている。
そしてこれらの各メソッドが、実際にブラウザから呼び出されるページと対応している。

今回はリスト表示の部分をいじるので

  def list
    @article_pages, @articles = paginate :articles, :per_page => 10
  end

の部分に注目。

詳細は省略するが、ここでは@articlesという配列にデータベースのarticlesテーブルからレコードを10件取得している。
この処理を行っているpaginateというメソッドにはいくつか引数でオプションを指定することができて、
上の上体では :per_page => 10 というオプションが指定されている。
呼んで字のごとく、一ページあたり10件のレコードを表示するということだろう。

ここにさらに :order_by というオプションを指定することで、記事のオーダー方法(ソート方法)を指定することができるようだ。
今回は、投稿降順(記事の投稿番号が大きいものが最初に表示される)で記事をリスト表示したいので、
:order_by => 'id desc'
というのを加えてみる。

  def list
    @article_pages, @articles = paginate :articles, :per_page => 10, :order_by => 'id desc'
  end

できた。

ちなみに一番最後に編集されたものが上にくるようにしたい場合は
:order_by => 'updated_at desc'
とすればよい。


長くて読みにくくなってきたので続きは明日にしよう