Ruby on Rails Tutorial (26)

ということで掘削対応に着手。とりあえず rake routes 確認。

$ rake routes
following_user GET    /users/:id/following(.:format) users#following
followers_user GET    /users/:id/followers(.:format) users#followers
         users GET    /users(.:format)               users#index
               POST   /users(.:format)               users#create
      new_user GET    /users/new(.:format)           users#new
     edit_user GET    /users/:id/edit(.:format)      users#edit
          user GET    /users/:id(.:format)           users#show
               PUT    /users/:id(.:format)           users#update
               DELETE /users/:id(.:format)           users#destroy
      sessions POST   /sessions(.:format)            sessions#create
   new_session GET    /sessions/new(.:format)        sessions#new
       session DELETE /sessions/:id(.:format)        sessions#destroy
    microposts POST   /microposts(.:format)          microposts#create
     micropost DELETE /microposts/:id(.:format)      microposts#destroy
 relationships POST   /relationships(.:format)       relationships#create
  relationship DELETE /relationships/:id(.:format)   relationships#destroy
          root        /                              static_pages#home
        signup        /signup(.:format)              users#new
        signin        /signin(.:format)              sessions#new
       signout DELETE /signout(.:format)             sessions#destroy
          help        /help(.:format)                static_pages#help
         about        /about(.:format)               static_pages#about
       contact        /contact(.:format)             static_pages#contact

redmine は横幅がパなかったですが、こちらはまだ規模的にもアレ。
ふと思いついたのですが、これって mindmap でプレゼンテーションできんかな。http://mind42.com/ にアカウントがあったはず、ということで作成着手。
root : static_pages#home から遷移可能なのは以下か。

  • help : static_pages#help
  • about : static_pages#about
  • contact : static_pages#contact
  • signup : users#new

ええと、これって header とか footer とかもアレですね。

  • signin : sessions#new
  • signout : sessions#destroy
  • users : users#index
  • edit_user : users#edit
  • user : users#show

む、あと以下もか。

  • micropost : microposts#create

あるいは following とか follower とかか。

  • following_user : users#following
  • followers_user : users#followers

なんかほとんど全部じゃんかorz
むむ、よくよく見たら自分のポストは削除可能だな。

  • micropost : microposts#destroy

このあたりで mindmap に反映させといて

  • static_pages
  • users
  • microposts
  • follow

なあたりの順で掘削してみるか。とりあえず現時点の mindmap も貼っておきます。
micropost
とりあえずここで一旦エントリ投入しといて掘削云々は追記の方向。

とりあえず static_pages な controller から

以下な定義。非常に簡単ですね。

class StaticPagesController < ApplicationController
  def home
    if signed_in?
      @micropost = current_user.microposts.build
      @feed_items = current_user.feed.paginate(page: params[:page])
    end
  end

  def help
  end

  def about
  end

  def contact
  end
end

始点なので app/views/layout 配下のソレも確認が必要なのか。ちなみに controller ですが root なアクションにて signed_in? であれば view で使われている変数に諸々の設定を行なっていらっしゃいますね。最初なので一つひとつ丁寧に掘ってみます。

  • signed_in? メソドについて
  • current_user について
  • User#microposts および build ってメソドについて
  • User#feed とか pagenate とか

上記確認後に app/views/layout 配下を云々。

signed_in? メソドについて

signed_in? は app/helpers/sessions_helper.rb にて定義されてます。app/helpers 配下って application_helper.rb と controller 作ったときに自動で作成されるヤツが、なんですかね。同じ名前のヤツがありますが。
でも今見てるのって static_pages_controller.rb だな。むむむ。
で、app/controllers/application_controller.rb 見てみたら以下な定義でした。

class ApplicationController < ActionController::Base
  protect_from_forgery
  include SessionsHelper
end

これで SessionHelper で定義されている属性はアプリケーショングローバルになるのか。つうかこれってどこで設定したんだろ。

git log app/controllers/application_controller.rb

で、以下な出力。今回のリポジトリはこれ系の探索が無意味だったりしますがorz

commit 52535ebf8cbb97bb0cae57d2f6c2147719b85f35
Author: YAMANE Toshiaki <yamanetoshi@gmail.com>
Date:   Fri Jan 25 19:55:23 2013 +0900

    Chapter 8 Sign in, sign out

commit d702fa72199dc441511c7ec08e528fd0db906708
Author: YAMANE Toshiaki <yamanetoshi@gmail.com>
Date:   Wed Jan 16 08:35:14 2013 +0900

    initial commit

む、Chapter 8 ですな。8.2.1 にて修正を盛り込んでおります。いやはや。しかし git は良い道具ですな。今回は使い方間違えちゃってるけどorz
app/helpers 配下については

  • application.rb はシステムグローバル
  • -helper.rb はその controller でのみ有効
  • 今回は app/controllers/application_controllers.rb で include されたのでシステムグローバルで sessions_helper.rb なソレ達が可視範囲になった

という理解で良いのかどうか

current_user について

signed_in? メソドは以下な定義になってて

  def signed_in?
    !current_user.nil?
  end

ここでも出てくる current_user というソレについても確認。
あ、current_user は SessionHelper の属性なんスね。イマサラですが使いかた的に面白くて以下が sign_in の定義。

  def sign_in(user)
    cookies.permanent[:remember_token] = user.remember_token
    self.current_user = user
  end

remember_token の詳細はここではスルーしますが、session cookie てきなソレを設定して current_user な属性に引数な User オブジェクトをセットしてます。
あるいは current_user な属性への setter が以下。

  def current_user=(user)
    @current_user = user
  end

これはそのまんまですね。その下に getter がありますがこれも面白い。

  def current_user
    @current_user ||= User.find_by_remember_token(cookies[:remember_token])
  end

サーバ側で session cookie が残ってたらそれを使おうとなさってらっしゃいます。つうか cookies てのは何かな。別途確認。

User#microposts および build ってメソドについて

app/models/user.rb で以下な記述があります。

  has_many :microposts, dependent: :destroy

関連する Micropost なオブジェクトを配列で保持してる形。あら、build て何でしょ。

      @micropost = current_user.microposts.build

ええと http://railsdoc.com/model には以下な記述がありますね。

新しいモデルを作り、多対多で関連付けるがDBは更新しない


おそらく一対多の typo だと思いますがこの micropost なオブジェクトは入力フォームのためにあるようですね。app/views/shared/_micropost_form.html.erb のソレ。
とりあえずこの程度でスルーします。

User#feed とか pagenate とか

以下な記述のソレ。

      @feed_items = current_user.feed.paginate(page: params[:page])

app/models/user.rb 見てみるに以下な記述がありますね。

  def feed
    Micropost.from_users_followed_by(self)
  end

app/models/micropost.rb の定義が以下。

  def self.from_users_followed_by(user)
    followed_user_ids = "SELECT followed_id FROM relationships
                         WHERE follower_id = :user_id"
    where("user_id IN (#{followed_user_ids}) OR user_id = :user_id",
          user_id: user.id)
  end

む、ここってかなりスルーしてるんだけど。よくよく見てみるとアレですね。つうかサブクエリなのか。たしか followed_user_ids に id な配列だかコンマ区切りの文字列だかを云々する場合件数が莫大だとアレじゃないですかね? 的問題に対応したものだったはず。なんとなくこのあたりも後天性記憶不全がorz
paginate も確認しておきます。
以下な gem が導入されております。

$ grep pag Gemfile
gem 'will_paginate', '3.0.3'
gem 'bootstrap-will_paginate', '0.0.6'

おそらく今ってこれがデフォなんだろうな。以下が git なリポジトリらしい。

app 配下を grep してみたら app/views 配下でも使われてますね。

$ find app/|xargs grep paginate
./app/views/users/show.html.erb:      <%= will_paginate @microposts %>
./app/views/users/show_follow.html.erb:      <%= will_paginate %>
./app/views/users/index.html.erb:<%= will_paginate %>
./app/views/users/index.html.erb:<%= will_paginate %>
./app/views/shared/_feed.html.erb:  <%= will_paginate @feed_items %>
./app/controllers/static_pages_controller.rb:      @feed_items = current_user.feed.paginate(page: params[:page])
./app/controllers/users_controller.rb:    @microposts = @user.microposts.paginate(page: params[:page])
./app/controllers/users_controller.rb:    @users = User.paginate(page: params[:page])
./app/controllers/users_controller.rb:    @users = @user.followed_users.paginate(page: params[:page])
./app/controllers/users_controller.rb:    @users = @user.followers.paginate(page: params[:page])

ちなみに app/views/users/index.html.erb ですが、最終版が以下。

<% provide(:title, 'All users') %>
<h1>All users</h1>

<%= will_paginate %>

<ul class="users">
  <%= render @users %>
</ul>

<%= will_paginate %>

なんだか凄いことになってます。これ、9.3 あたりで云々されている模様。最初はこんなカンジだったのですが

<% provide(:title, 'All users') %>
<h1>All users</h1>

<ul class="users">
  <% @users.each do |user| %>
    <li>
      <%= gravatar_for user, size: 52 %>
      <%= link_to user.name, user %>
    </li>
  <% end %>
</ul>

9.3.3 で will_paginate が導入されたのか。全然記憶に無い。

gem 'will_paginate', '3.0.3'
gem 'bootstrap-will_paginate', '0.0.6'

Listing 9.34 で以下になっています。

<% provide(:title, 'All users') %>
<h1>All users</h1>

<%= will_paginate %>

<ul class="users">
  <% @users.each do |user| %>
    <li>
      <%= gravatar_for user, size: 52 %>
      <%= link_to user.name, user %>
    </li>
  <% end %>
</ul>

<%= will_paginate %>

成程。view で使うとここからここまで pagination してね、って意味になるのかな。とは言え、app/views/users/show_html.erb だと以下な記述があったりとか

    <% if @user.microposts.any? %>
      <h3>Microposts (<%= @user.microposts.count %>)</h3>
      <ol class="microposts">
        <%= render @microposts %>
      </ol>
      <%= will_paginate @microposts %>
    <% end %>

あるいは app/views/users/show_follow.html.erb で以下な記述があったりとか

    <% if @users.any? %>
      <ul class="users">
        <%= render @users %>
      </ul>
      <%= will_paginate %>
    <% end %>

ここでの使われかた、はどうなのか。あるいは先の類推はダウトなのかビンゴなのか。

cookies について

デフォで用意されちゃってる模様。

app 配下 grep したら以下なカンジ。

$ find app |xargs grep cookies
app/helpers/sessions_helper.rb:    cookies.permanent[:remember_token] = user.remember_token
app/helpers/sessions_helper.rb:    @current_user ||= User.find_by_remember_token(cookies[:remember_token])
app/helpers/sessions_helper.rb:    cookies.delete(:remember_token)
app/helpers/sessions_helper.rb~:    cookies.permanent[:remember_token] = user.remember_token
app/helpers/sessions_helper.rb~:    @current_user ||= User.find_by_remember_token(cookies[:remember_token])
app/helpers/sessions_helper.rb~:    cookies.delete(:remember_token)

とりあえず

一旦手を置いてばんめし製造に着手します。とりあえず残りとして

  • will_paginate の view での使われかた
  • app/views/layout 配下を云々

が継続。