kouの技術的メモ

学習した内容の定着やアウトプット用に開設しました

成果物の作成7 投稿とその表示部分の実装

ここからは自作の要素が強くなるので、じっくり作っていきたいと思います。

投稿モデルの作成

投稿部分は、タイトルと本文を収納したオリジナルモデルを作ります user_idを外部キーとし、本文部分は文字数に長文を投稿できるようにtext型にします。 また、タイトル部分はstring型で実装します。 投稿が新しものを一番上に表示したいので、後でcreated_atを

今回作ったPostモデル app/models/post.rb マイグレーションファイルは20190204050217_create_posts.rb |属性|データ型| |:---|:---| |ID|integer| |title|string| |content|text| |user_id|integer| |created_at|datetime| |update_at|datetime|


あるpostは誰か一人のuserのものなので、 belongs_toメソッドで関連付けを行い

投稿された時間が新しいものを上に表示させたいので、Postモデルにデフォルトスコープで降順を指定します

app/models/post.rb

 belongs_to :user
 default_scope -> { order(created_at: :desc) }


あるuserはいくつものpostを持っているので、Userモデルにもhas_manyメソッドを追加し、

削除されたときには、関連付けたpostも同時に削除されるようにdependent: :destroyを追加します

app/models/users.rb

  has_many :posts, dependent: :destroy


投稿表示部分の実装

seedsに吐き出してもらうサンプルデータですが

Faker gemについて調べたところ、ちょうどFaker::Name.title

でいい感じにデータを吐き出してくれそうなので

title  = Faker::Name.title 

にします。

また、記事一覧表示機能ですが、 bootstrapのcardを使い、タイトル、本文、投稿者名、投稿日時を表示します。

本文はtruncateメソッド利用して、50文字だけ省略表示します。 また、続きを読む、にリンクを指定して、記事詳細表示ページへのリンクとします。

投稿日時はUTCのままだったので、app/config/application.rbでconfig.time_zone = 'Asia/Tokyo'にしてJST日本時間にします。

また、このままだとUTCとの時間差+0900がついていて、少し見にくいので strftimeメソッドを使い、秒までの表記とします

application_helperに以下のsimple_timeメソッドを作り、viewで<%= simple_time(post.created_at) %>で表示させるようにしました。

 def simple_time(time)                                   #日付をJSTに変え<+0900の表記が邪魔な為日付を見やすくする。
    time.strftime("%Y-%m-%d %H:%M ")                                          #strftimeメソッドで表示させる日付時刻を設定。
  end

また、それらに対してテストを書いていきます。

投稿画面作成

基本的には _post_formパーシャルに投稿画面を作ります 本文は入力フォームを大きくしたほうがいいので、rows:15にしました。

<%= form_for(@post) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
      <%= f.label :タイトル %>
      <%= f.text_field :title,placeholder: "ここにタイトルを書き込んでください...", class: 'form-control' %>
      
      <%= f.label :記事本文 %>
      <%= f.text_area :content,placeholder: "ここに本文を書き込んでください...", class: 'form-control', rows:15 %>
      
  <%= f.submit "投稿", class: "btn btn-primary" %>
<% end %>

home画面でログインユーザーのみ投稿画面を表示したいので、

<% if logged_in? %>
  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <%= render 'shared/user_info' %>
      </section>
      <section class="post_form">
        <%= render 'shared/post_form' %>
      </section>
    </aside>
  </div>
<% else %>
  <div class="center jumbotron">
    <h1>Kohei's blog</h1>

    <h2>
      This is the home page  Kohei's blog
    </h2>

    <%= link_to "Sign up now!",  signup_path, class: "btn btn-lg btn-primary" %>
  </div>
<% end %>

とコーディングします。

記事詳細表示機能

ルーティングは以下とします

メソッド パス アクション
get /users/id又はpost_path(post) show

ほぼ、記事一覧で使用したものと同じですが、本文の改行などが反映されません。

調べたところ、Railsはデータベースには改行情報はそのまま保存されているらしいのですが、そのままではhtmlに反映してくれないみたいなので、

simple_formatメソッドを使って、記事本文の全文を表示させます

<% provide(:title, @post.title) %>
<div class="card">
    <h5 class="card-header">タイトル: <%= link_to @post.title %></h5>
    <div class="card-body">
        <p class="card-text">本文 : <%= simple_format(@post.content) %> </p>
    </div>
    <div class="card-footer">
      投稿者<%= link_to @post.user.name, user_path(@post.user.id) %>  - 投稿日時<%= simple_time(@post.created_at) %>
      <% if current_user?(@post.user) %>
      <%= link_to "削除", @post, method: :delete,
                                       data: { confirm: "You sure?" } %>
    <% end %>
    </div>
</div>

これからテストを書いていくわけですが、記事一覧表示機能のテストで少しハマりました

本当は改行も含めたテストをしたかったのですが、統合テストでsimple_formatメソッドとsanitizeメソッドも色々試した結果使えず、

タグや、
を使っているhtmlファイルとの比較ができなかったため、アルファベッドを大量に生成してテストをすることにし、改行のテストは実際に動作確認をすることにしました。

content = "a" * 30 + "b" * 30  
assert_match Post.first.content.truncate(50), response.body

S3を使った画像アップロード機能も追加して、投稿とその表示部分の実装が完成です。