坊やがゆく

2006-10-20 Railsでソーシャルブックマークを作ってみようか(第1回)

Railsでソーシャルブックマークを作ってみようか(第1回)

第1回

masuidriveさんベース

最新LLフレームワークエクスプローラより


はじめに

Railsアプリを作る「はじめの一歩」としての足がかりになればと思いまとめました。

また、Railsに慣れて「××分でできる」にチャレンジするための規程課題になるといいなぁと野望を持ってます。

さあ君も勉強会でボクとタイムアタック!


ちなみに環境のインストールとかは省略します。環境に関してはこちらのサイト様を参考にして下さい。


OSWindowsを想定していますが大きな違いは無いと思います(たぶん)。

CUIでもIDEでもお好きな物をお使い下さい。

なお、細かい解説は無しの方向で。手順の列挙のみ行いますのでご了承ねがいます。


ソーシャルブックマークを作ってみよう

■プロジェクトを始める

rails bookmark


データベースの準備

mysql -u -root -p

create database bookmark_development default character set utf8;

余談

C:\rails_apps\bb>mysql -u -root -p

Enter password: ****

ERROR 1045 (28000): Access denied for user '-root'@'localhost' (using password:YES)

このエラーが出たり出なかったり…謎。現状はたまたま上手くいくのを祈ってます。

phpMyAdminの導入を本気で考えた方が良いかもしれない)


データベースを使う設定

config/database.ymlを編集

development:
  adapter: mysql
  database: bookmark_development
  username: root
  password: ****
  host: localhost
  encoding: utf8

■itemsテーブルを作成

db/items.sqlを作成してMySQLに流し込む

drop table if exists items;
create table items (
  id                integer         not null auto_increment,
  url               varchar(255)    not null,
  title             varchar(255)    not null,
  description       text            not null,
  primary key(id)
);

mysql -u root -p bookmark_development < db/items.sql


■itemモデル/コントローラの作成(CRUD処理の実装)

ruby script/generate scaffold item item


■日本語化

config/enviroment.rbを編集

$KCODE = 'u'

# Be sure to restart your web server when you modify this file.

app/controllers/application.rbを編集

class ApplicationController < ActionController::Base
  before_filter :set_charset
  protected
  def set_charset
    @headers["Content-Type"] = "text/html; charset=utf-8"
  end
end

WEBrickの起動

ruby script/server


■いくつか登録する

http://localhost:3000/item/


■並びを登録の逆順にする

itemコントローラのlistアクションを編集

def list
  @item_pages, @items = paginate :items, :per_page => 10, :order_by => 'id desc'
end

■見た目を直す

itemビューのlist.rhtmlを編集

<dl>
<% for item in @items %>
<dt><a href="<%=h item.url %>"><%=h item.title %></a></dt>
<dd><%=h item.description %>
    <%= link_to '[Show]', :action => 'show', :id => item %>
    <%= link_to '[Edit]', :action => 'edit', :id => item %>
    <%= link_to '[x]', { :action => 'destroy', :id => item }, :confirm => 'Are you sure?', :post => true %>
</dd>
<% end %>
</dl>

<%= link_to 'Previous page', { :page => @item_pages.current.previous } if @item_pages.current.previous %>
<%= link_to 'Next page', { :page => @item_pages.current.next } if @item_pages.current.next %> 
<br />

<%= link_to 'New item', :action => 'new' %>

■バリデーションの追加

itemモデルを編集

class Item < ActiveRecord::Base
  validates_presence_of :url, :title
  validates_format_of :url, :with=>/:\/\//
  validates_length_of :description, :within=>0..512
end

■検索機能の追加

itemコントローラのlistアクションを編集

def list
  if @params[:keyword]
    keyword = "%"+@params[:keyword]+"%"
    @item_pages, @items = paginate :items, :per_page => 10, :order_by => 'id desc', :conditions => ["url LIKE ? OR title LIKE ? OR description LIKE ?", keyword, keyword, keyword]
  else
    @item_pages, @items = paginate :items, :per_page => 10, :order_by => 'id desc'
  end
end

itemビューのlist.rhtmlを編集

<%= form_tag :action => "list" %>
キーワード:<input name="keyword" value="<%=h @params[:keyword] %>"/>
<%= submit_tag "検索" %>
<%= end_form_tag %>

■LoginGeneratorをインストール

gem install login_generator --remote


■usersテーブルを作成

db/users.sqlを作成してMySQLに流し込む

drop table if exists users;
create table users (
  id                integer         not null auto_increment,
  login             varchar(255)    default null,
  password          varchar(255)    default null,
  primary key(id)
);

mysql -u root -p bookmark_development < db/users.sql


■userモデル/コントローラの作成(コントローラ名はaccount)

ruby script/generate login account


■認証を実装する

app/controllers/application.rbを編集

class ApplicationController < ActionController::Base
  include LoginSystem
  model :user

accountコントローラのwelcomeアクションにリダイレクトを記述

def welcome
  redirect_to :action => "list", :controller => "item"
end

itemコントローラに制限を記述

class ItemController < ApplicationController
  before_filter :login_required

■サインアップ

http://localhost:3000/account/signup/


■ログアウト

http://localhost:3000/account/logout/


ログインユーザ名を表示する

itemビューのlist.rhtmlを編集

ようこそ<%= @session['user'].login %>さん

ログインする

http://localhost:3000/item/


■itemsテーブルに外部キーを追加する

mysql -u -root -p

ALTER TABLE bookmark_development.items ADD user_id integer;

UPDATE bookmark_development.items SET user_id = 1;

itemモデルにbelongs_toを記述

class Item < ActiveRecord::Base
  belongs_to :user

userモデルにhas_manyを記述

class User < ActiveRecord::Base
  has_many :item

■複数ユーザに対応

itemコントローラを編集

class ItemController < ApplicationController
  before_filter :login_required

  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
    if @params[:keyword]
      keyword = "%"+@params[:keyword]+"%"
      @item_pages, @items = paginate :items, :per_page => 10, :order_by => 'id desc', :conditions => ["user_id = ? AND (url LIKE ? OR title LIKE ? OR description LIKE ?)", @session['user'].id, keyword, keyword, keyword]
    else
      @item_pages, @items = paginate :items, :per_page => 10, :order_by => 'id desc', :conditions => ["user_id = ?", @session['user'].id]
    end
  end

  def show
    @item = Item.find(params[:id], :conditions => ["user_id = ?", @session['user'].id])
  end

  def new
    @item = Item.new
  end

  def create
    @item = Item.new(params[:item])
    @item.user_id = @session['user'].id
    if @item.save
      flash[:notice] = 'Item was successfully created.'
      redirect_to :action => 'list'
    else
      render :action => 'new'
    end
  end

  def edit
    @item = Item.find(params[:id], :conditions => ["user_id = ?", @session['user'].id])
  end

  def update
    @item = Item.find(params[:id], :conditions => ["user_id = ?", @session['user'].id])
    if @item.update_attributes(params[:item])
      flash[:notice] = 'Item was successfully updated.'
      redirect_to :action => 'show', :id => @item
    else
      render :action => 'edit'
    end
  end

  def destroy
    Item.find(params[:id], :conditions => ["user_id = ?", @session['user'].id]).destroy
    redirect_to :action => 'list'
  end
end

完成!

おつかれさまでした。


今後の展開や問題点など

次の内容を反映する。

高橋さんベース
Railsアプリを作ってみようかセッションRails勉強会@東京第11回)より
Depotアプリケーション
RailsによるアジャイルWebアプリケーション開発より
RailsによるアジャイルWebアプリケーション開発

RailsによるアジャイルWebアプリケーション開発

  • 作者: 前田修吾
  • 出版社/メーカー: オーム社
  • 発売日: 2006/02/25
  • メディア: 単行本(ソフトカバー)
レストラン・ガイド
一目でわかるRuby on Railsより

次の問題を解決したいなぁ(弱気)

  • ログアウト、サインアップなどに遷移できない。
  • 現状はURLを直接入力することでカバーする。
  • ブックマークしたユーザ数のカウントがないのでソーシャルっぽくない。