ちょっとしたSNSもどきをつくってみた(1)

SNSもどきを作る

ログイン機能は必須だろう。restful_authenticationプラグインデファクトスタンダードらしい。メールを使ってサインアップもできたりするらしいけど、ちょっとソースを追っかけるレベルでないので後回し
http://d.hatena.ne.jp/tsimo/20080323/1206277929)をみてやりました
新しくプロジェクトを作る。

$ rails rails_sns_1

プラグインをインストールする

$ script/plugin install git://github.com/technoweenie/restful-authentication.git

生成

$ script/generate authenticated user sessions
$ db:migrate
$ script/server

あとは適当にテーブルを作っておく

$script/generate scaffold post user_id:integer title:string text:text

どんなものが作られたか。まずconfig/routes.rb

  # ログイン画面用。login_path
  map.login 'login', :controller => 'sessions', :action => 'new'
  # ログアウト用。logout_path
  map.logout '/logout', :controller => 'sessions', :action => 'destroy'
  # サインアップ画面。signup_path
  map.signup '/signup', :controller => 'users', :action => 'create'
  # 登録。register_path
  map.register '/register', :controller => 'users', :action => 'new'
  
  # ユーザリソースとセッションリソース
  map.resources :users
  map.resource :session
  • sessionsコントローラはログイン(セッション生成)/ログアウト(セッション破棄)用
  • usersコントローラはサインアップ用(登録画面/登録処理)
  • 後ろのmap.resource(s)は拡張用でしょうか。使ってないよね?
  • sessionはシングルトンリソースとして設定されている。そうやって使うのか
  • RESTfulとうたうなら、/logoutとかはアウト?すなおに/sessionをDELETEするほうがそれっぽい?

コントローラ。SessionsControllerとUsersControllerに書いてある下のinclude文をApplicationControllerに移動した

  include AutuenticatedSystem
  • このコントローラでは認証システムを使うよ、ということらしい。ApplicationControllerに書けば全体に適用される
  • また、before_filter :login_required とするとログインしてない場合は自動的にログインページ(/sessions/new)に飛ばしてくれる
  • ApplicationControllerに書いといて、不要なところだけskip_before_filterするのが楽チンそう

モデル。userのみ。

  • おおざっぱに、includeしてるところ、validateしてるところ、と追加のクラスメソッド(authenticate)に分かれる

ここまでの動きはなんとなくわかった。ので、今回作るもの

  • レイアウトは、左メインコンテンツ。右にアカウント情報(ログインしてなかったらログインフォーム)
  • トップページには、すべてのユーザのpostを新しい順に並べる(ついでにコメント数も)
  • users/1/postsでそのユーザが書いたpostが見えます
  • postはそのユーザしか編集できません
  • profileテーブルとか作って、さらに画像とかもアップロードできたらいいな

まずは関連

class User < ActiveRecord::Base
  〜いろいろ省略〜
  has_many :posts
end

class Post < ActiveRecord::Base
  belongs_to :user
end

レイアウト
posts.html.erbをリネームしてapplication.html.erbとする(つかいまわし用)。
ナビゲーションバーの中身を共通化したくて、こんなことしたんだけど、いいのかな?

<!-- ナビゲーション -->
<div id="navi">
<%= render(:partial => 'layouts/navi') -%>
</div>

パーシャルの中身。logged_in?でログイン中かどうかがわかる
正直、あまりきれいじゃない。。

<div class="block">
<%- if logged_in? -%>
<h3>ログイン中</h3>
<p>こんにちは、<%=h current_user.name %>さん</p>
<%- else -%>
<h3>ログインしてください</h3>
<% form_tag session_path, :class => "mini_login_form" do %>
<%= render :partial => 'sessions/form' -%>
<%- end -%>
<%- end -%>
</div>

ルーティングを変えました。
/users/1 で1ばんさんのトップページ
/users/1/posts で1ばんさんのpostの一覧ページにいくようなイメージです

  map.resources :users do |user|
    user.resources :posts
  end

自分いがい書けないようにするために、以下のようにした。いいのかな?

  def auth_check
    unless logged_in? && @current_user == @user
      flash[:error] = "あなたにはこの日記への書き込み権限がありません"
      redirect_to user_posts_path(@user)
    end
  end

before_filterでfalseを返してもその後の処理は継続される。falseでチェインを停止するのは、1.xの仕様らしい。だまされた。。
自分いがいの場合は「編集」ボタンとかを表示しないようにするために、ヘルパーメソッドを追加した。おなじチェックなのに、ちょっと無駄な気が。

  def writable?
    logged_in? && (current_user == @user)
  end

今日はこんなところまで。けっこうきれいになった