CodeZine(コードジン)

特集ページ一覧

Curl+JRuby+Google App EngineでTwitter風アプリを作る
~ローカル環境構築編~

第4回

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2009/08/27 14:00
目次

Twitter風サービスの構築

 さて、Twitterクライアントが完成しました。今度は自分たちの手でTwitter風サービス(Twitterクローン)を作成してみましょう。Twitter風サービスを作るには、以下の3つのテーブル(=モデル)が必要になります。

  • 利用者(users)
    • 利用者の名前、画像、認証用情報
  • 友人、フォローしている人(friendships)
    • 利用者がフォローしている人
  • つぶやき(status)
    • つぶやきの内容、つぶやいた日時

 テーブルの関連は下のER図のようになります

 これから、このTwitter風サービスのコードを説明していきます。今回は紙面の都合もありますのでView(テンプレート)の説明は省略しました。

 まず、「tinytter」という名前でプロジェクトを作成し、テーブル情報を元にscaffoldを使ってひな形を作成します。

> jruby -S rails tinytter
> cd tinytter
>  jruby -S scrip/generate scaffold status text:string user_id:integer
>  jruby -S scrip/generate scaffold user screen_name:string password:string profile_image_path:string 
>  jruby -S scrip/generate scaffold friendship user_id:integer friend_id:integer

 JRuby はC言語で作られたRDBのドライバー等を直接呼び出せないので、sqlite3はJDBC経由でアクセスしています。そこで config/database.yml ファイルの adapter: を sqlite3 から jdbcsqite3 に変更して下さい。

applicationコントローラー

 最初に各コントローラーが継承しているapplicationコントローラーを簡単に説明します。

 layout で全View共通のレイアウトファイル app/view/layout/scaffold.html.erbを指定しています。

 before_filter でコントローラー内の各処理(アクション)の実行前に実行される処理を定義しています。ここではauthenticateメソッドでBasic認証を行っています。認証が失敗し、このメソッドが false を戻した場合はアクションは実行されません。またこのメソッド内で利用者のユーザーidをインスタンス変数 @user_id に設定しています。

class ApplicationController < ActionController::Base
  helper :all 
  protect_from_forgery 
  filter_parameter_logging  :password
  
  layout "scaffold"
  before_filter :authenticate

  private

  def authenticate
    authenticate_or_request_with_http_basic do |user_name, password|
      @user_id = User.authenticate(user_name, password)
    end
  end
end

利用者モデル

 usersテーブルには、friendshipsテーブル、statusesテーブルに一対多の関連がありますので has_manyで宣言しています。ActiveRecord(Ruby on RailsのO/Rマッパー)ではテーブルの関連をモデルに定義する事で、簡単に関連したテーブルの情報を扱えるようになります。

 authenticateメソッドはscreen_name、passwordを受け取り認証を行うクラスメソッドです。認証が成功した場合は利用者のidが戻ります。また、今回はパスワードを暗号化していません。アイコン画像はプログラムをシンプルにするため、ユーザー登録時に予め用意された画像から選択する方式にしました。 profile_image_selectorメソッドはアイコン画像のパス名一覧を戻します。

 after_create{...} ですがuserモデルのデータをテーブルに新規作成する際に実行される処理を定義しています。ここではユーザー登録時に自分自身を自分の友人としてfriendshipsに登録しています。このように自分自身を友人に登録する事でつぶやき表示に自分のつぶやきが表示されるようにしています。

 ActiveRecordでは、このようにデータの変更・作成の前後に独自の処理を追加できます。

class User < ActiveRecord::Base
  has_many :friendships
  has_many :statuses
  
  def self.authenticate(screen_name, password)
    user = self.find_by_screen_name(screen_name)
    (user && user.password == password) ? user.id : nil
  end

  IMAGES_DIR = "./public/images/"
  PROFILE_IMAGES_DIR = "profile_images"
  
  def self.profile_image_selector
    Dir.glob(IMAGES_DIR + PROFILE_IMAGES_DIR + "/*").map {|path| path.sub(IMAGES_DIR, '')}
  end
  
  after_create {|rec| Friendship.create_self(rec.id)}

end

利用者コントローラー

 ユーザー情報の登録、表示、変更、削除を行います。ほぼscaffoldのコードですが、XML関連出力を取り除きました。またパラメータでidを指定するのではなく、認証されたユーザーidに対して表示・変更・削除を行うようにしています。

 skip_before_filter ... でユーザーの登録、トップページの処理では認証を外しています。

class UsersController < ApplicationController
  
  skip_before_filter :authenticate, :only => [:top, :new, :create]

  def index
    @user = User.find(@user_id)
  end

  def new
    @user = User.new
  end

  def edit
    @user = User.find(@user_id)
  end

  def create
    @user = User.new(params[:user])

    if @user.save
      flash[:notice] = 'ユーザー登録しました'
      redirect_to(:action => :top)
    else
      render :action => "edit"
    end
  end

  def update
    @user = User.find(@user_id)

    if @user.update_attributes(params[:user])
      flash[:notice] = 'ユーザー情報を変更しました'
      redirect_to(users_url)
    else
      render :action => "edit"
    end
  end

  def destroy
    @user = User.find(@user_id)
    @user.destroy
    redirect_to(users_url)
  end
  
  def top
  end

end

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 吉田裕美(ヨシダユウミ)

    有限会社 EY-Office 取締役 CADのベンチャー企業でCADのコア部分や図面管理システムなどの開発に従事した後、独立しJava,Ruby,PerlでWebアプリを中心に開発してきた。現在は殆どの開発はRuby on Rails。 ここ数年はソフトウェアエンジニアの教育に興味をもち、従来の...

バックナンバー

連載:Ruby on Rails + Curl
All contents copyright © 2005-2020 Shoeisha Co., Ltd. All rights reserved. ver.1.5