Rails + Cicindelaでレコメンデーション付ウェブサイトの構築(1)

目次

  1. ユーザ認証付Railsアプリの構築   ←いまここ
  2. RailsアプリにCicindelaインタフェースを実装
  3. Cicindelaの設定とバッチ処理設定

 
先日Sapporo.rbで黙々と読書した成果として、Ruby on RailsのアプリにCicindelaのレコメンデーション機能をつけることができました。そんなわけで何回かに分けて説明していきます。

まずはRailsアプリを作ります。お題としてはソーシャルブックマークサービスにしてみます。ブックマークアプリはRailsの課題曲みたいなもので、慣れた人なら10分で作れます。今回はそれに加えてユーザごとにブックマークできるよう、ログイン認証などの機能拡張が必要になります。

完成版のソースコードgithubにて公開しています。

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

今回の環境としてはこんな感じです。
 OS: Ubuntu 8.04
 Ruby: 1.8.6
 Ruby on Rails: 2.2.2
 MySQL: 5.0.51

とりあえずプロジェクト作成。

rails bookmark -d mysql
cd bookmark
データベースの作成
mysql -uroot -ppass -e "create database bookmark;"

管理者名、パスワードは適当に読み替えてください。
config/database.ymlを編集。

 database: bookmark
 username: root
 password: pass
認証プラグインのインストール

ログイン認証はrestful_authenticationを使うことにします。

script/plugin install
http://svn.techno-weenie.net/projects/plugins/restful_authentication/
script/generate authenticated user sessions

app/controllers/users_controller.rbを編集して以下の行をコメントアウト

  #include AuthenticatedSystem

その代わりapp/controllers/application.rbに以下の行を追加。

  include AuthenticatedSystem

これだけで認証機能ができてしまいます、簡単簡単。プログラムで制御したり表示する場合などはcurrent_user.idでユーザIDが、current_user.loginでユーザ名が取得できます。

アプリケーション雛形の生成

さて、テーブル設計ですが、こんな感じ。ひとつのウェブページに対して複数の人がブックマークしてコメントできるようにします。レコメンデーションが本題なのでアプリの機能としては必要最小限で。


script/generate scaffold Webpage url:string title:string
script/generate scaffold Bookmark user_id:integer webpage_id:integer comment:string

User関係はrestful_authenticationが作ってくれているのでテーブルもクラスも自作する必要はありません。

テーブル間の関連設定

app/models/bookmark.rbを編集し、belongs_toを追加。

 class Bookmark < ActiveRecord::Base
   belongs_to :user
   belongs_to :webpage

app/models/user.rbを編集、has_manyを追加。

 class User < ActiveRecord::Base
   has_many :bookmarks

app/models/webpage.rbを編集、has_manyを追加。

 class Webpage < ActiveRecord::Base
   has_many :bookmarks
テーブル作成
rake db:migrate
アクセス制限設定

login_requiredを追加することで、ログアウト状態の時はアクセスできなくなります。
app/controllers/bookmarks_controller.rb、app/controllers/webpagess_controller.rbを編集

 before_filter :login_required
コントローラの設定

こんな感じ。
app/controllers/bookmarks_controller.rb(一部)

class BookmarksController < ApplicationController
  before_filter :login_required

  def index
    @bookmarks = Bookmark.find_all_by_user_id(current_user.id, :order => 'updated_at desc', :include => :webpage)
  end

  def create
    @webpage = Webpage.find_by_url(params[:webpage][:url])
    if @webpage.nil?
      @webpage = Webpage.new(params[:webpage])
      unless @webpage.save
        render :action => "new"
      end
    end
 
    @bookmark = Bookmark.find_by_user_id_and_webpage_id(current_user.id, @webpage.id)
    if @bookmark.nil?
      @bookmark = Bookmark.new(:user_id => current_user.id, :webpage_id => @webpage.id)
    end
    @bookmark.comment = params[:bookmark][:comment]
    if @bookmark.save
      flash[:notice] = 'Bookmark was successfully created.'
      redirect_to(bookmarks_url)
    else
      render :action => "new"
    end
  end

 (省略)

indexメソッドでは、自分のブックマークだけを更新順に取得しています。
createメソッドでは、新規ブックマークしたときに該当するwebpagesのレコードがなかったら(まだ誰もそのページをブックマークしていなかったら)、bookmarksテーブルだけでなくwebpagesにもレコードを追加するようにしています。

ビューの設定

まあ適当にこんな感じで。
app/views/bookmarks/index.html.erb

<h2><strong><%=h current_user.login %></strong>さんのブックマーク</h2>
<% for bookmark in @bookmarks %>
   <h1><%= link_to bookmark.webpage.title, :controller => 'webpages', :action => 'show', :id => bookmark.webpage_id %></h1>
   <span class="url"><%= link_to bookmark.webpage.url, bookmark.webpage.url %></span><br />
   <%=h bookmark.comment %><br />
 
   <%= link_to '編集', edit_bookmark_path(bookmark) %>
   <%= link_to '削除', bookmark, :confirm => 'Are you sure?', :method => :delete %>
<% end %>

新規ブックマーク画面ではwebpageの情報も入力するようにします。
app/views/bookmarks/new.html.erb

<h1>新規ブックマーク</h1>
 
<% form_for(@bookmark) do |f| %>
  <%= f.error_messages %>
 
  <p>
    <%= label :webpage, "Title" %><br />
    <%= text_field :webpage, :title %>
  </p>
  <p>
    <%= label :webpage, "URL" %><br />
    <%= text_field :webpage, :url %>
  </p>
  <p>
    <%= f.label :comment %><br />
    <%= f.text_field :comment %>
  </p>
  <p>
    <%= f.submit "Create" %>
  </p>
<% end %>
 
<%= link_to 'Back', bookmarks_path %>

ウェブページ詳細画面(冒頭のスクリーンショット)では、このページをブックマークしているユーザの一覧を表示します。後でここにレコメンデーション一覧も追加する予定。
app/views/webpages/show.html.erb

<h1>ブックマーク詳細</h1>
 
<h1><%=h @webpage.title %></h1>
<span class="url"><%= link_to @webpage.url, @webpage.url %></span>
<br />
 
<h3>◆このページをブックマークしているユーザ</h3>
<table>
<% for bookmark in @bookmarks %>
  <tr>
    <td><strong><%=h bookmark.user.login %></strong></td>
    <td><%=h bookmark.comment %><br /></td>
  </tr>
<% end %>
</table>
 
<%= link_to 'Edit', edit_webpage_path(@webpage) %> |
<%= link_to 'Home', bookmarks_path %>

それ以外にもリンク先の変更だとか、スタイルシート設定とかもろもろありますがここでは省略。
 
起動します。

script/server

できた。(/localhost:3000/bookmarks)


長くなったので今回はここまで。次回はCicindela側の設定と、Railsとの連携について書く予定です。