Hatena::Diary

篳篥日記 このページをアンテナに追加 RSSフィード

2008-12-07 Railsで作るTwitterもどき (5) このエントリーのブックマークコメント

[Rails] Railsで作るTwitterもどき (ヘルパ、ビュー編)

これまでの流れ:

Railsで作るTwitterもどき (1) モデル編他

Railsで作るTwitterもどき (2) URL設計

Railsで作るTwitterもどき (3) 下準備 2

Railsで作るTwitterもどき (4) コントローラ


まず、全体的なレイアウトを決めておく。

ヘッダとフッタがあって、中身がある感じ。

f:id:hichiriki:20081207133758p:image


app/views/layouts/ にレイアウト用のファイルを作る。

全体のレイアウト

app/views/layouts/layout.html.erb

<%= render :partial => "layouts/header" %>
<%= @content_for_layout %>
<%= render :partial => "layouts/footer" %>

ヘッダ

app/views/layouts/_header.html.erb

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="Content-Script-Type" content="text/javascript" />
    <title>twitterもどき</title>
    <%= javascript_include_tag :defaults %>
    <%= stylesheet_link_tag "style" %>
    <%= @content_for_header %>
  </head>
  <body>
    <div style="text-align: right; margin-right: 2em;">
      <% if logged_in? %>
        <%= link_to 'home', home_path %> |
        <%= link_to 'ログアウト', logout_path %>
      <% else %>
        <%= link_to 'ログイン', login_path %>
      <% end %>
    </div>

ヘッダにはログイン、ログアウト用のリンクも用意しておいた。


フッタ

app/views/layouts/_footer.html.erb

    <%#= debug(params) %>
    <%#= debug(session) %>
  </body>
</html>

debug(params) とかはデバッグ用に入れておくと良いかも。コメントアウトしている # を取ると、paramsやsessionの中身が表示されるようになる。


ApplicationControllerで、いま定義したレイアウトを使用するようにする。

# app/controllers/application.rb
class ApplicationController < ActionController::Base
  # 略
  layout "layout"
  # 略
end

次にヘルパを用意する。

大体使いそうなものをリストアップして、それぞれ使いそうな場所を想定して実装。

  • ユーザのページへのリンク
  • 個別発言へのリンク
  • つぶやき削除用リンク
  • つぶやきが自分のつぶやきかどうかを調べるヘルパ

この辺を実装してみる。


全体から使いそうなものは application_helperへ。

# app/helpers/application_helper.rb
module ApplicationHelper
  # ユーザへのリンク
  def link_to_user(user)
    link_to h(user.login), :controller => :members, :action => :show, :user => user.login
  end
end

つぶやき関連は tweets_hepler へ。

# app/helpers/tweets_helper.rb
module TweetsHelper
  # 個別発言へのリンク
  def link_to_tweet(tweet)
    link_to h(tweet.created_at.to_s(:jp)), 
      { :controller => :tweets, :action => :show, :user => tweet.user.login, :id => tweet.id }
  end

  # つぶやき削除用リンク
  def link_to_destroy(tweet)
    link_to '削除', :controller => :tweets, :action => :destroy, :id => tweet.id if params[:controller] == "members"
  end

  # 自分のつぶやきかどうか
  def my_tweet?(tweet)
    tweet.user_id == current_user.id
  end
end

個別発言へのリンクは、本家Twitterと同じく発言日時にリンクを張る。

ここでは簡単のため、つぶやき削除は、自分のページからしか行えないことにする。


あとはゴリゴリとviewを書いていくだけ。


自分のホーム。

app/views/members/home.html.erb

<div id="page" class="clearfix">
  <div id="content">
    <%= render :partial => 'content' %>
  </div>

  <div id="sidebar">
    <%= render :partial => 'sidebar' %>
  </div>
</div>

partialで分割。


つぶやき用formと、つぶやき一覧。

app/views/members/_content.html.erb

<%- if logged_in? -%>
<% form_for :tweet, :url => { :action => :update } do |f| %>
  いまなにしてる?<br />
  <%= f.text_field :body, :style => "padding: 0.5em; font-size: 1.2em;" %>
  <%= f.submit "投稿する" %>
<% end %>
<%- end -%>

<div id="tweets">
  <%= render :partial => '/members/tweets' %>
</div>

つぶやき欄はちょっと大きくしておいた。


つぶやき一覧。

will_paginateでページ送り。

app/views/members/_tweets.html.erb

<%- @tweets.each do |t| -%>
  <%= link_to_user(t.user) %> :
  <%= h t.body %>
  <span class="timestamp">(<%= link_to_tweet(t) %>)</span>
  <%- if logged_in? -%>
    <%= link_to_destroy(t) if my_tweet?(t) %>
  <%- end -%>
  <br />
<%- end -%>
<p>
  <%= will_paginate @tweets, :previous_label => "&laquo; 前へ", :next_label => "&raquo; 次へ" %>
</p>

サイドバーにはユーザ名他の情報を。

このサイドバーは自分のホームと、その他のユーザのページで使い回すので、条件分岐で表示するものを若干変えてある。

app/views/members/_sidebar.html.erb

<%- if logged_in? && me? -%>
  <h1><%= h @user.login %></h1>
  <p>
    あなたがフォロー: <%= link_to h(@user.friends.size), friends_path %><br />
    あなたをフォロー: <%= link_to h(@user.followers.size), followers_path %><br />
    これまでの投稿: <%= link_to h(@user.tweets.size), :controller => :members, :action => :show, :user => @user.login %>
  </p>
<%- else -%>
  <p>
    あなたがフォロー: <%= link_to h(@user.friends.size), :controller => :members, :action => :friends, :user => @user.login %><br />
    あなたをフォロー: <%= link_to h(@user.followers.size), :controller => :members, :action => :followers, :user => @user.login %><br />
    これまでの投稿: <%= link_to h(@user.tweets.size), :controller => :members, :action => :show, :user => @user.login %>
  </p>
<%- end -%>

<p>
  <%= link_to '公開つぶやき', :controller => :tweets, :action => :list %>
</p>

<div id="friends">
  フォロー中
  <br />
  <%- @user.friends.each do |u| -%>
    <%= link_to_user(u) %> &nbsp;
  <%- end -%>
</div>

他ユーザのページ。

app/views/members/show.html.erb

<div id="page" class="clearfix">
  <div id="content">
    <h1><%= h @user.login %></h1>
    <%- if logged_in? && !me? -%>
      <p>
        <%= link_to_remote friend? ? "フォロー解除" : "フォローする", { :url => { :controller => :members, :action => :ajax_toggle_follow, :id => @user.id } }, :id => 
"follow" %>
      </p>
    <%- end -%>
    <div id="tweets">
      <%= render :partial => '/members/tweets' %>
    </div>
  </div>
  <div id="sidebar">
    <%= render :partial => 'sidebar' %>
  </div>
</div>

ログインしていて、自分自身では無いときだけ、フォロー、フォロー解除のリンクを表示。

フォロー、フォロー解除は、このページからだけ行えることにした。Ajaxなので link_to_remote。


ここで使っている friend? というヘルパは、自分がフォローしているユーザかどうかを返すもの。以下のようにApplicationControllerに追加しておいた。

関連テーブルを調べて、自分がフォローしているユーザかどうかを返す。

# app/controllers/application.rb
class ApplicationController < ActionController::Base
  # 略
  helper_method :me?, :friend?

  # 略
  protected

  def friend?
    !me? && !!Friendship.find_by_user_id_and_friend_id(@current_user.id, @user.id)
  end

自分がフォローしているユーザの一覧。

app/views/members/friends.html.rb

<div id="page" class="clearfix">
  <div id="content">
    <h1><%= h @user.login %> がフォロー</h1>

    <%- @friends.each do |u| -%>
      <%= link_to_user u %><br />
    <%- end -%>
    <p>
      <%= will_paginate @friends, :previous_label => "&laquo; 前へ", :next_label => "&raquo; 次へ" %>
    </p>
  </div>
</div>

自分のフォロワー一覧。

app/views/members/followers.html.erb

<div id="page" class="clearfix">
  <div id="content">
    <h1><%= h @user.login %> をフォロー</h1>

    <%- @followers.each do |u| -%>
      <%= link_to_user u %>
    <br />
    <%- end -%>
    <p>
      <%= will_paginate @followers, :previous_label => "&laquo; 前へ", :next_label => "&raquo; 次へ" %>
    </p>
  </div>
</div>

個別発言(1つのつぶやきへのパーマリンク)。

app/views/tweets/show.html.erb

<div id="page">
  <h1><%= link_to_user(@tweet.user)  %></h1>

  <span style="font-size: larger;"><%= h @tweet.body %></span>
  <br />
  (<%= h @tweet.created_at.to_s(:jp) %>)
</div>

公開つぶやき一覧。

app/views/tweets/list.html.erb

<div id="page" class="clearfix">
  <div id="content">
    <%= render :partial => '/members/tweets' %>
  </div>
</div>

最後に、適当な二段組みのスタイルシートを用意してみる。

public/stylesheets/style.css

.clearfix:after {
  content: ".";
  display: block;
  clear: both;
  height: 0px;
  visibility: hidden;
}

#page {
  width: 900px;
  margin: 0;
  margin-left: auto;
  margin-right: auto;
  padding: 0;
}

#sidebar {
  float: right;
  width: 200px;
  height: auto;
}

#content {
  float: left;
  width: 650px;
  height: 600px;
  padding: 1em;
  border-right: solid 1px #ccc;
}

.timestamp {
  color: #aaa;
}

.timestamp a {
  color: #aaa;
  text-decoration: none;
}

.timestamp a:hover {
  color: #00f;
  text-decoration: underline;
}

なんだか駆け足になってしまったが、これで一通りはできあがりだ。

f:id:hichiriki:20081207144044p:image

Railsで作るTwitterもどき、これ以降は「お気に入り」機能を足したりといった事を書こうかと思う。

大西大西 2010/02/11 06:14 このRailsで作るTwitterもどきを有料でわけていただけますか?当方のサイトで運営したく思います。どうかよろしくお願いします。

hichirikihichiriki 2010/02/11 12:27 このページの通りに作ってしまえば、誰でも無料でできますよ。

ただし、このTwitterもどきはRailsのチュートリアルとして説明用に作ったものですので、リプライ機能などTwitterには存在する基本的な機能も備えていません。またアクセスが集中した場合のスケールアウトなどに関しても、考慮されていません。
その辺りはご了承ください。

hichirikihichiriki 2010/02/11 13:05 コメントにメール欄(非公開)がありますので、どうしてもという場合は連絡先メールアドレスを記入してください。
よろしくお願いします。

大西大西 2010/02/11 16:20 ありがとうございます。メールアドレスを記入しました。厚かましいお願いですが、できれば当方のサーバーに設置して戴ければ幸甚です。
今後の開発も含めてご相談にのって戴ければ幸甚です。いいドメインを取得致しましたもので、、、