0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Railsチュートリアル 第13章 ユーザーのマイクロポスト - マイクロポストの描画

Posted at

開発環境のデータベースのリセット

演習等で生成したマイクロポストの影響を排除するため、一旦開発環境のデータベースをリセットします。

# rails db:migrate:reset
Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'

== [timestamp] CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0186s
== [timestamp] CreateUsers: migrated (0.0202s) =============================

...略

== [timestamp] CreateMicroposts: migrating =================================
-- create_table(:microposts)
   -> 0.0163s
-- add_index(:microposts, [:user_id, :created_at])
   -> 0.0035s
== [timestamp] CreateMicroposts: migrated (0.0206s) ========================

# rails db:seed

rails db:seedは、正常に完了した場合、何のメッセージも表示することなくシェルに戻ります。

Micropostsコントローラーの作成

これからMicropostのコントローラーとビューが必要となります。そのため、rails generate controllerコマンドで自動生成していきます。

# rails generate controller Microposts
Running via Spring preloader in process 1783
      create  app/controllers/microposts_controller.rb
      invoke  erb
      create    app/views/microposts
      invoke  test_unit
      create    test/controllers/microposts_controller_test.rb
      invoke  helper
      create    app/helpers/microposts_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/microposts.coffee
      invoke    scss
      create      app/assets/stylesheets/microposts.scss

なお、「マイクロポストの表示」という機能に必要となるのはビューのみです。コントローラーのほうは、「Web経由でマイクロポストを操作するためのインターフェースの実装」以降に使っていくことになります。

1つのマイクロポストを表示するパーシャル

復習 - ユーザーの一覧表示はどのように記述していたか

Usersコントローラーのindexアクションに対応する埋め込みRubyでは、以下のようにしてrenderメソッドを用いることにより、Userモデルに含まれるユーザーを一覧表示していました。

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

Userモデルに対応するビューにおいて、@users内に含まれるユーザーのコレクションをrenderメソッドの引数として取った場合、各ユーザー個別の表示内容に対応するパーシャルは、app/views/users/_user.html.erbという名前なのでしたね。

マイクロポストの一覧表示はどのように記述するか

@microposts内に含まれるマイクロポストを一覧表示すためのrenderメソッドは、以下のようにして用います。前述「@users内に含まれるユーザーの一覧表示」と酷似していますね。

<ol class="microposts">
  <%= render @microposts %>
</ol>

重要なポイントは以下です。

  • 順序なしリストを表すul要素ではなく、順序付きリストを表すol要素を用いる
    • マイクロポストの順序には、「時系列順」という明確な意味があるため
  • 対応するパーシャルはapp/views/microposts/_micropost.html.erbである
    • app/views/microposts/_micropost.html.erbの内容を記述していく必要がある

ユーザーの場合との大きな違いは、「順序なしリストであるulではなく、順序付きリストであるolを用いている」という点です。これは、「マイクロポストには順序(新しい→古い)がある」という仕様に依拠するものです。

app/views/microposts/_micropost.html.erbの内容

app/views/microposts/_micropost.html.erb
<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
  <span class="content"><%= micropost.content %></span>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
  </span>
</li>

time_ago_in_wordsメソッドとは

time_ago_in_wordsというヘルパーメソッドを使っていることがポイントです。time_ago_in_wordsメソッドは、RailsのActionView::Helpers::DateHelperモジュールに存在するメソッドで、「○分前に投稿」といった文字列を出力するものです。

各マイクロポストのビューに対し、CSSのidを割り振る

<li id="micropost-<%= micropost.id %>">

上記li要素では、マイクロポストのIDを元として、CSSをのIDを割り振っています。一般に「Webデザインのベストプラクティス」とされる手法であり、例えば、「Javascriptを使って各マイクロポストを操作する」といったユースケースで役に立つことが期待されます。

Usersコントローラーに、マイクロポストのページネーションに必要な実装を追加する

「ユーザーのshowページで直接マイクロポストを表示する」というユースケースの場合、対応するページネーションの実装は以下のようになります。

<%= will_paginate @microposts %>

以前に行った「ユーザーのindexページへのページネーションの実装」とは異なり、will_paginateメソッドに明示的に引数@micropostsを渡しています。「引数の有無が異なる」という違いがあるからには、何らかの違いがあるはずです。

will_paginateに引数が必要となる理由

ユーザーのindexページにおけるページネーションの実装と、ユーザーのshowページにおけるページネーションの実装。何が違うのかといいますと、「Usersコントローラー内でUserモデルに対しての処理を行っているのか、あるいはそうでないのか」ということです。この違いが、引数の要不要の違いにつながってきます。

「Usersコントローラー内でUserモデルに対してwill_paginateメソッドを実行する」という場合、will_paginateに引数は必要ありません。暗黙的に@usersが対象であるとみなされます。一方、「Usersコントローラー内でMicropostモデルに対してwill_paginateメソッドを実行する」というような場合、will_paginateには「どのモデルを対象とするか」を表す引数が必要になります。Micropostモデルが対象であれば@micropostsですね。

UsersController#showに、@micropostsそのものの定義を追加する

UsersController#showには、@micropostsというインスタンス変数そのものの定義も必要になります。

app/controllers/users_controller.rb
  class UsersController < ApplicationController
    ...略

    def index
      @users = User.where(activated: true).paginate(page: params[:page])
    end

    def show
      @user = User.find(params[:id])
+     @microposts = @user.microposts.paginate(page: params[:page])
      redirect_to root_url unless @user.activated?
    end

    ...略
  end

indexアクションにおける@usersの定義と同様、panigateメソッドを使っています。

(復習になりますが)コントローラーにおけるpanigateメソッドは、ビューにおけるwill_paginateメソッドと対応しています。今回用いているpaginateメソッドは、Userモデルにおけるhas_many :micropostsや、Micropostモデルにおけるbelongs_to :userといった定義を通じて、Micropostテーブルに対して必要な処理を実行することができるのです。

マイクロポストの投稿数を表示する

ユーザーに対するマイクロポストの投稿数のカウントは、以下のメソッドで行うことができます。

user.microposts.count

上記コードの動作における重要なポイントは、「マイクロポストの数をカウントする処理は、Ruby環境側ではなく、RDB側で行われている」ということです。「マイクロポストの数をカウントする」などといった処理の場合、RDB側での計算処理は高度に最適化されています。高度に最適化されているということは、それだけ計算が高速、ということであるのです。

プロフィール画面へのマイクロポストの表示機能を実装する

編集対象はapp/views/users/show.html.erbとなります。編集内容については、以下の別記事にて言及しています。

実装完了時点でのプロフィール画面の表示

なお、上記実装が完了した時点でプロフィール画面をWebブラウザにて表示すると、結果は以下のようになります。

スクリーンショット 2019-12-26 15.57.26.png

マイクロポストが1件もないので、今までの画面と表示内容は変わりません。

RDBのmicropostsテーブルに対して、SQLのSELECT文が発行されるようになった

一方で、Railsサーバーには以下のようなログが記録されています。

Started GET "/users/1" for ...略
Processing by UsersController#show as HTML
  Parameters: {"id"=>"1"}
  User Load (5.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  Rendering users/show.html.erb within layouts/application
  Micropost Exists (2.7ms)  SELECT  1 AS one FROM "microposts" WHERE "microposts"."user_id" = ? LIMIT ?  [["user_id", 1], ["LIMIT", 1]]
  Rendered users/show.html.erb within layouts/application (5.1ms)
  Rendered layouts/_rails_default.erb (282.3ms)
  Rendered layouts/_shim.html.erb (0.3ms)
  User Load (2.8ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  Rendered layouts/_header.html.erb (5.6ms)
  Rendered layouts/_footer.html.erb (0.5ms)
Completed 200 OK in 459ms (Views: 421.6ms | ActiveRecord: 10.6ms)
Micropost Exists (2.7ms)  SELECT  1 AS one FROM "microposts" WHERE "microposts"."user_id" = ? LIMIT ?  [["user_id", 1], ["LIMIT", 1]]

確かにmicropostsテーブルに対してSQLのSELECT文が発行されています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?