この記事では、Micropostsにおける投稿機能について、簡単に理解したのでその確認として理解を深めることを目的としている。
投稿機能は以下の手順デコーディングを行う
- Micropostモデル、contentカラム、user_idカラム(外部キー)を作る
- UserテーブルとMicropostテーブルを関連付ける
- UsersコントローラーのshowアクションにMicropostの中身を表示させるための「@microposts」を記載する
- Usersフォルダーのviewのshow.html.erbにも@micropostsを記載する
- Micropostsコントローラーを作り、_micropost.html.erbにmicropostテーブルのcontentカラムの中身を表示させるファイルを作る
- Homeページをアップデートする
1.Micropostモデル、contentカラム、user_idカラム(外部キー)を作る
$ rails g model Micropost content:string user_id:integer
↓
$ rails db:migrate:reset db:seed
↑データベースをいじったので一度migrateファイルをリセットしておく
Microposは誰の投稿化を知るために必ずuser_idを持たなければいけないので以下のコードを打ち込む
class Micropost < ActiveRecord::Base
*** validates :user_id, presence: true
end
UserテーブルとMicropostテーブルを関連付けをする
models/micropost.rb
class Micropost < ApplicationRecord
*** belongs_to :user
validates :user_id, presence: true
end
models/user.rb
class User < ApplicationRecord
*** has_many :microposts, *dependent: :destroy
...
end
最新の投稿が投稿欄の一番上に表示されるようにする
class Micropost < ApplicationRecord
belogns_to :user
*** default_scope -> { order('created_at DESC')}
validates :user_id, presence: true
end
*dependent: :destroyを使うことによりuserが退会した場合にそのuserが投稿した内容も同時に削除されるようにする
投稿文字数をTwitterのように140文字以内でしか投稿できないようにする
class Micropost < ApplicationRecord
belongs_to :user
default_scope -> {order('created_at DESC')}
*** validates :content, presence: true, length: { maximum: 140 }
validates :user_id, presence: true
end
3. UsersコントローラーのshowアクションにMicropostの中身(content)を表示させるための「@microposts」を記載する
class UsersController <
ApplicationController
///
def show
@user = User.find(params[:id])
@microposts = @user.microposts.paginate(page: params[:page], per_page: 12)
#userに紐づくすべての投稿をpaginateで取得する。
end
<% provide(:title, @user.name)%>
<div class="container pt-4">
<div class="row">
<aside class="span">
<section>
<h1>
<%= gravatar_for @user %>
<%= @user.name%>
</h1>
</section>
</aside>
<div class="col-9">
<div>
<% if @user.microposts.any?%>
#モデルにデータが存在する→true/存在しない→falseを返すメソッド
<h3>Microposts (<%= @user.microposts.count %>)</h3>
<ol class="microposts">
<%= render @microposts%>
</ol>
<%= will_paginate @microposts%>
<% end %>
</div>
</div>
5. Micropostsコントローラーを作り、_micropost.html.erbにmicropostテーブルのcontentカラムの中身を表示させるファイルを作る
rails g controller Microposts
=>createアクションとdestroyアクションを作るためにmicropostsコントローラーを作る
<li>
<h4><%= micropost.content%></h4>
#micropostテーブルのcontentカラムの内容を表示
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
#created_atで作成日時を表示する際に、Twitterのように「~前」と表示する方法 ※ex:約19時間前
</span>
</li>
=> showページでmicroposts投稿内容と作成日を表示させる
▼Fakerでダミーデータを作成する
users = User.order(:created_at).take(7)
50.times do
content = Faker::Lorem.sentence(3)
users.each { |user| user.microposts.create!(content:content) }
end
$rails db:migrate:reset db:seed
=> データベースの中身を変更したのでリセットする
createとdestroyのルーティングをresourcesメソッドを使って定義する
///
resources :users
resources :sessions, only: [:new, :create, :destroy]
resources :microposts, only: [:create, :destroy]
///
6. Homeページをアップデートする
<% provide(:title, 'Home')%>
<% if logged_in?%>
<div class="row">
<aside class="col-3">
<section>
<%= render 'shared/user_info' %>
</section>
<section>
<%= render 'shared/micropost_form' %>
</section>
</aside>
<!-- Microposts here -->
</div>
<% else %>
<h1 style="text-align:center;">Awesome Blog</h1>
<p>
Welcome to Awesome Blog!<br>
</p>
<p>
This Blog is made for all people who want to get good shape of the body!!
</p>
=>userがログインしているときは投稿機能とユーザーの情報を表示するがログインしていないときはAwesome Blogを表示するようにする
<%= link_to gravatar_for(@user, size: 52), @user%>
<h1>
<%= @user.name%> #usersデーブルのnameカラム
</h1>
<span>
<%= pluralize(@user.microposts.count, "micropost")%>
#pluralizeヘルパー...最初の引数に整数があると、それに基づいて2番目の引数である英単語が複数形に変化したものが渡される。
</span>
<%= form_for(@micropost) do |f| %> #特定のモデルに特化したフォームを作りたい → form_for
<div>
<%= f.text_area :content, placeholder: "Compose new micropost...", class: "w-100"%>
</div>
<%= f.submit "Post", class: "btn btn-block btn-primary" %>
<% end %>
=>form_forメソッドを使うとモデルのインスタンスを渡すだけで自動的にRailsが処理してくれる(RESTfulなリソースを使っている場合)
form_for(@micropost)の@micropostがすでに保存されていた場合にはupdateアクション、未保存の時はcreateアクションを、Railsは自動的に選んでくれる※@micropostは後でhomeコントローラーで定義する
micropostsコントローラーのcreate,destroyアクションにアクセスできるのはログインを正しくしたユーザだけに制限する
before_action :only_loggedin_users, only: [:create, :destroy]
def create
end
def destroy
end
=>before_actionをすることによりURLから直接アクセスされることを防ぐ(ログインしていなければログインページにとぶ)
micropostsコントローラーの中身を記載していく
before_action :only_loggedin_users, only: [:create, :destroy]
def create
@micropost = current_user.microposts.build(micropost_params)
#microposts_paramsとは下のprivateで定義したもの
#.build≒.new
if @micropost.save
flash[:success] = "Successfully saved!"
redirect_to root_url
else
flash[:danger] = "Invalid content. Try again."
redirect_to root_url
end
end
def destroy
end
private
def micropost_params
params.require(:micropost).permit(:content)
end
=>投稿内容を@micropostに格納し保存するに成功したらflashメッセージを表示させ(flash[:success]=)homeページに投稿を反映させる(redirect_to root_url)
class StaticPagesController < ApplicationController
def home
@micropost = current_user.microposts.build if logged_in? #1対多の場合では、「関連付けメソッド名.build」となる
end
def about
end
def contact
end
end
=>現在ログインしているユーザーモデルに紐づく投稿のオブジェクトを作成する
▼すべての投稿を表示する
<% if logged_in?%>
<div class="row">
<aside class="col-3">
<section>
<%= render 'shared/user_info' %>
</section>
<section>
<%= render 'shared/micropost_form' %>
</section>
</aside>
<!-- Microposts here -->
<div class="col-9">
<h3>Micropost Feed</h3>
*** <%= render 'shared\feed'%>
</div>
</div>
<% else %>
=>_feed.html.erbに投稿一覧を表示するようにする
def home
#@micropost = current_user.microposts.build if logged_in?
if logged_in?
@micropost = current_user.microposts.build
@feed_items = current_user.feed.paginate(page: params[:page], per_page: 12)
#user.rbで定義したfeedメソッドをの取得結果を@feed_itemsに格納する
@user = current_user
end
end
=>homeアクションのリファクタリングを行う。
///
def feed
Micropost.where("user_id = ?", id)
end
///
=>この部分がいまいち理解できない
<% if @feed_items.any? %>
<ol>
<%= render partial: 'shared/feed_item', collection: @feed_items %>
</ol>
<%= will_pagenate @feed_items %>
<% end %>
<li class="col-12 my-4">
<%= link_to gravatar_for(feed_item.user), feed_item.user %>
<span class="user">
<%= link_to feed_item.user.name, feed_item.user %>
</span>
<h4><%= feed_item.content %></h4>
<span class="timestamp">
Posted <%= time_ago_in_words(feed_item.created_at) %> ago.
</span>
</li>
///
def create
@micropost = current_user.microposts.build(micropost_params)
if @micropost.save
flash[:success] = "Successfully saved!"
redirect_to root_url
else
*** @feed_items = []
flash[:danger] = "Invalid content. Try again."
redirect_to root_url
end
end
///
=>@feed_items = []を加えることで@feed_itemsの中に何も入っていない(nil)の時に発生するエラーを防ぐ
削除機能を作る
<li>
<h4><%= micropost.content%></h4>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
</span>
***
<% if current_user?(micropost.user) %>
<%= link_to "delete", micropost, method: :delete,
data: { confirm:"Are you sure?"}
title: micropost.contentn %>
<% end %>
***
</li>
=>ログインしているユーザーのshowページにだけ削除機能があらわれるようにする
<li class="col-12 my-4">
<%= link_to gravatar_for(feed_item.user), feed_item.user %>
<span class="user">
<%= link_to feed_item.user.name, feed_item.user %>
</span>
<h4><%= feed_item.content %></h4>
<span class="timestamp">
Posted <%= time_ago_in_words(feed_item.created_at) %> ago.
</span>
***
<% if current_user?(feed_item.user) %>
<%= link_to "delete", feed_item, method: :delete,
data: { confirm: "You sure?"}
title: feed_item.content %>
<% end %>
***
</li>
destroyアクションの中身を記載する
def destroy
Micropost.find(params[:id]).destroy
redirect_to root_url
end