成果物の作成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を使った画像アップロード機能も追加して、投稿とその表示部分の実装が完成です。