Rails で楽々ソーシャルブックマークの仕組みを作る

こんにちは。Ruby(とRails)を担当している石原です。
前回に引き続き、ソーシャル「OSを入れた後にインストールする10のアプリケーション」(仮)を作っていきます。以降、サイトの名前は 10 Best Application on New Install から取って 10best とします。
これまでのエントリーはこちら↓
- つくるぶガイドブログ: ひとりサービスの雛型をつくる(リキッドレイアウト、GetText、Acts as Authenticated)
- つくるぶガイドブログ: Ruby on Rails を使ってひとりでサービスを作ってみよう
10best では、アプリケーションをダウンロードできる場所のURLを登録して、みんなで共有していきます。いわばソーシャルブックマークの、ブックマーク先をアプリケーションのダウンロードページに限定したものです。
今回は以下のような流れで基礎となるソーシャルブックマークの仕組みを作っていきます。
- モデルの作成
- フォームのエラー処理
- ブックマーク作成の処理を整える
- データが空のときの画面デザイン
モデルの作成
まずはモデルの作成です。
ソーシャルブックマークでは、最初に誰かがページをブックマークして、別の人が同じページをブックマークすることが考えられます。タイトルなどのページ固有の情報は、そのページを登録したブックマークすべてで共有したいので、ページとブックマークを別々のモデルとし、ページには複数のブックマークがひもづくという構成にしたいと思います。
10best ではページにあたるものがソフトウェアなので、Software と Bookmark という2つのモデルを作成します。
コマンドラインより、
script/generate model Software
script/generate model Bookmark
を実行すると、モデルのクラスファイルや Migration ファイルが作成されます。
Migration ファイルは以下の通り編集します。
== db/migrate/004_create_softwares.rb ==
class CreateSoftwares < ActiveRecord::Migration
def self.up
create_table :softwares do |t|
t.column :title, :string
t.column :url, :string
t.column :created_at, :datetime
t.column :updated_at, :datetime
end
end
def self.down
drop_table :softwares
end
end
== db/migrate/005_create_bookmarks.rb ==
class CreateBookmarks < ActiveRecord::Migration
def self.up
create_table :bookmarks do |t|
t.column :software_id, :integer, :null => false
t.column :user_id, :integer, :null => false
t.column :created_at, :datetime
t.column :updated_at, :datetime
end
end
def self.down
drop_table :bookmarks
end
end
rake db:migrate
を実行すれば、DB 上に softwares と bookmarks のテーブルが用意されます。
Sotware と Bookmark は 1対多 の関係、User と Bookmark も 1対多 の関係(1人のユーザーが複数のブックマークを持てる)なので、モデルのクラスファイルを以下のように編集します。
== app/models/software.rb == class Software < ActiveRecord::Base has_many :bookmarks end
== app/models/bookmark.rb == class Bookmark < ActiveRecord::Base belongs_to :user belongs_to :software end
Rails のモデルを考えるとき、複数形と単数形がごっちゃになってわかりにくくなることがあります。そういうときは、英語脳で考えるようにして、対象となるものが1個しかないものなのか複数あるものなのかを具体的に考えるようにすると理解しやすいと思います。
has_many の場合は many とあることから次にくるのは複数形とわかりますし、script/generate model のあとに来るモデル名は、モデルは抽象的な名前でモノではないですから、単数形である、といったように考えます。
コードの中の変数名に対しても、それが配列で複数のモノを指すなら複数形を、1個のモノしか入らないのなら単数形を使うようにして、常に複数か単数かを考える癖をつけておくといいと思います。
フォームのエラー処理
エラー処理を書くのは好きですか?
あまり好きだという人を聞いたことがありませんが、フォームのエラー処理が楽に実装できる、というのが Rails の醍醐味の一つではないでしょうか。
まず、フォーム処理の雛型を Scaffold 機能で作ってしまいます。
script/generate scaffold Software
を実行すると、Software を表示、作成、編集、削除するひととおりの画面と処理が出来上がります。たとえば作成画面は以下の通り。
次にエラー処理を追加します。
登録するソフトウェアのページのタイトルと URL は必ず入力するようにし、タイトルは最大100文字、URLは最大 200 文字としておきます。また、URL は重複を許さない、といった制限を Rails で書くと、以下のようになります。
== app/models/software.rb == class Software < ActiveRecord::Base has_many :bookmarks validates_presence_of :title validates_length_of :title, :maximum => 100 validates_presence_of :url validates_length_of :url, :maximum => 200 validates_uniqueness_of :url end
以上のコードだけで、この制限にひっかかる値がフォームから入力されたとき、以下のようなエラーメッセージが自動的に表示されるまで実装できてしまいます。
ブックマーク作成の処理を整える
ソフトウェアのページを登録すると同時に、ブックマークを作成します。すでにそのページが存在している、つまり同じ URL を持つページが他にある場合には、そのページにひもづいたブックマークが作成されるような処理を書きます。
== app/controllers/softwares_controller.rb ==
def create
# 同じURLを持った別のページが存在するか?
@software = Software.find_by_url(params[:software][:url])
unless @software
# 存在しなければ新たに作成
@software = Software.new(params[:software])
end
bookmark = Bookmark.new
if @software.save
# ソフトウェアのページとブックマークをひもづけ、
bookmark.software_id = @software.id
# ログインしているユーザーのブックマークに追加
current_user.bookmarks << bookmark
flash[:notice] = 'Software was successfully created.'
redirect_to :action => 'list'
else
render :action => 'new'
end
end
ユーザーのブックマークの一覧ページが必要なので、Bookmark モデルに関連した一覧ページなども Scaffold で作成しておきます。
script/generate scaffold Bookmark
ブックマーク一覧ではログインしたユーザーのブックマークだけが表示されるよう、コントローラーの list アクションは以下のように書きます。
== app/controllers/bookmarks_controller.rb ==
def list
@bookmark_pages, @bookmarks = paginate(
:bookmarks,
:conditions => ['user_id = ?', current_user.id],
:order => 'created_at DESC',
:per_page => 10
)
end
/bookmarks/list からブックマークを作成するとき、実際に呼び出すのは、Software モデルの作成画面、つまり /softwares/create になるようビューを変更します。
== app/views/bookmarks/list.rhtml == <%= link_to 'New bookmark', :action => 'new' %> を <%= link_to 'New software', :controller => 'softwares', :action => 'new' %> に変更する
そのほか、レイアウトを整えたり、/softwares/create のあと、ブックマーク一覧ページである /bookmarks/list にリダイレクトされるようにしたり、ログイン直後も同様に /bookmarks/list にリダイレクトされるよう、細かな修正をおこないます。
エントリーの一番最後にソースコードへのリンクを掲載しておきますので、実際にコードを読んで確認していただければと思います。
データが空のときの画面デザイン
初回で紹介した Getting Real の The Blank Slate というセクションでは、「データが空の場合の画面デザインを忘れるな」と説いています。
開発環境でテストを続けていると、テストデータをどんどん入力するので、データが実際に入っている状態での画面をいつも見ているわけです。しかしユーザーが最初に見る画面というのは、何もデータが入っていない画面、つまり 10best で言えば、ブックマークが全くない状態の一覧画面になります。
それは次のような画面になります。
データが何もない一覧画面というものは味気ないものです。
データが何も入っていない場合には、例えば、サイトのチュートリアルやスクリーンキャストなど、ユーザーにこれから使ってもらうための工夫を施すべきだ、というのが Getting Real の主張です。
試しに、ユーザーにすぐにブックマークを促すメッセージを表示し、文字サイズを大きくして強調してみました。
まとめ
モデルを作成し、Scaffold で簡単ですがコントローラーやビューを用意し、エラー処理も整えました。
ここまでのソースコードをアップロードしておきました。
» 10best - Google Code
svn checkout http://10best.googlecode.com/svn/trunk/ 10best
でチェックアウトするか、ブラウザでもリポジトリを閲覧することができます。




最近のコメント