Railsチュートリアル13章
テストコードはRspecで書いています。
・複合キーインデックス
micropostのマイグレーションファイル
def change
create_table :microposts do |t|
t.text :content
t.references :user, null: false, foreign_key: true
t.timestamps
end
add_index :microposts, [:user_id, :created_at] ここ!!
end
end
複数のキーをセットで扱うことができる。
こうすることでuser_idに紐付けられたmicropostsを作成順(今回は作成の逆順にする)で取り出す
・default scope
Micropostモデル
class Micropost < ApplicationRecord
belongs_to :user
has_one_attached :image
default_scope -> { order(created_at: :desc) } ここ!!
このようにして作成の逆順で取り出すよう設定している。
time_ago_in_wordsメソッド
<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 %>
<%= image_tag micropost.display_image if micropost.image.attached? %>
</span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
ここ!!
<% if current_user?(micropost.user) %>
<%= link_to "delete", micropost, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</span>
</li>
何分前とかって出るようにする。例えば3分前、3時間前、3日前。
マクロポストの作成(build)
root_pathのhomeでuserに紐ずくmicropostを作成する。
何かに紐付いたものを生成する場合、newではなくbuildになる。
作成はhomeで保存はmicropostのcreate
class StaticPagesController < ApplicationController
def home
if logged_in?
@micropost = current_user.microposts.build
ここ!!
@feed_items = current_user.feed.paginate(page: params[:page])
end
end
micropostのcreateアクションがこれでmergeでuser_id:current_user.idってしてないんだよね。だからcurrent_user.buildってしてるんだ
def create
@micropost = current_user.microposts.build(micropost_params)
@micropost.image.attach(params[:micropost][:image])
if @micropost.save
redirect_to root_url
else
@feed_items = current_user.feed.paginate(page: params[:page])
render 'static_pages/home'
end
end
def micropost_params
params.require(:micropost).permit(:content, :image) ここねmergeしてない
end
referrer
feed
userモデル
def feed
Micropost.where("user_id = ?", id)
end
?を使うことでidをエスケープしている
ここのidとは右側のこと。self.idのことつまりはUser.id
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
def home
if logged_in?
@micropost = current_user.microposts.build
@feed_items = current_user.feed.paginate(page: params[:page]) ここ!!
end
end
app/views/static_pages/home.html.erb
<div class="col-md-8">
<h3>Micropost Feed</h3>
<%= render 'shared/feed' %>
</div>
app/views/shared/_feed.html.erb
<% if @feed_items.any? %>
<ol class="microposts">
<%= render @feed_items %> ここ!!
</ol>
<%= will_paginate @feed_items,
params: { controller: :static_pages, action: :home } %>
<% end %>
<%= render @feed_items %>
@feed_itemsはMicropostsのクラスを持っているため、micropostsのパーシャルを呼び出すことができた。_micropost.html.erbを呼び出してる
microposts作成失敗の場合に備えて
app/controllers/microposts_controller.rb
def create
@micropost = current_user.microposts.build(micropost_params)
@micropost.image.attach(params[:micropost][:image])
if @micropost.save
redirect_to root_url
else
@feed_items = current_user.feed.paginate(page: params[:page]) ここ!!
renderする際に@feed_itemsを渡してる
render 'static_pages/home'
end
end
ページネートでエラーが出るので解決。
micropostsをcreateするcreateアクションがMicropostsコントローラーにあるので、Micropostsコントローラーでページネートしようとしている。
そこで、コントローラーとアクションを指定してあげることで解決する。
app/views/shared/_feed.html.erb
<% if @feed_items.any? %>
<ol class="microposts">
<%= render @feed_items %>
</ol>
<%= will_paginate @feed_items, ここ!!
params: { controller: :static_pages, action: :home } %>
コントローラーとアクションを指定
<% end %>
テストコード(Rspec)
factorybot
FactoryBot.define do
factory :micropost do
content { Faker::Lorem.sentence }
# created_at { 10.minutes.ago }
association :user
end
trait :yesterday do
content { "昨日" }
created_at { 1.day.ago }
end
trait :now do
content { "今" }
created_at { Time.zone.now }
end
trait :one_week_ago do
content { "1週間前" }
created_at { 1.week.ago }
end
end
モデルテスト micropost
require 'rails_helper'
before do
@micropost = FactoryBot.create(:micropost)
ここはbuildじゃダメだった。
end
it "should be valid" do
expect(@micropost).to be_valid
end
it "user id should be present" do
expect(@micropost).not_to be_valid
end
it "content should be present" do
@micropost.content = " "
expect(@micropost).not_to be_valid
end
@micropost.content = "a" * 141
expect(@micropost).not_to be_valid
end
end
before do
factroybot見て
@one_week_ago = FactoryBot.create(:micropost,:one_week_ago)
@now = FactoryBot.create(:micropost,:now)
@yesterday = FactoryBot.create(:micropost,:yesterday)
end
expect(Micropost.first).to eq @now
end
end
before do
@micropost = FactoryBot.create(:micropost)
end
it 'associated microposts should be destroyed' do
expect do
@micropost.user.destroy
end.to change(Micropost, :count).by(-1)
end
end
system spec micropost
equire 'rails_helper'
before do
@user = FactoryBot.create(:user)
@micropost = FactoryBot.create(:micropost)
# @microposts = FactoryBot.create_list(:micropost, 32)
ここ!! micropost34個分作ってる
34.times do
content = Faker::Lorem.sentence(word_count: 5)
@user.microposts.create!(content: content)
end
end
it 'user/showのmicroposts' do
log_in(@user)
visit user_path(@user)
Micropost.paginate(page: 1).each do |micropost|
# expect(page).to have_link href: user_path(micropost.user)
expect(page).to have_content(micropost.user.name)
expect(page).to have_content(micropost.content)
end
end
log_in(@user)
visit root_path
expect(page).to have_content("34 microposts") s
log_in(@micropost.user)
visit root_path
expect(page).to have_content("1 micropost") sなし
end
it 'micropost interface 全体の流れ(micropost)' do
log_in(@user)
visit root_path
expect(page).to have_link"Next"
# これでページネーションあること(30個以上micropostあること)示す
fill_in 'micropost_content', with: "How are you?"
# labelがない場合idでもいい micropost_contentはid
画像のテスト!
attach_file('micropost[image]', image_path, make_visible: true)
これはname
# attach_file 'micropost_image', with: "#{Rails.root}/spec/fixtures/kitten.jpg"
expect do
find('input[name="commit"]').click
end.to change { Micropost.count }.by(1)
expect do
ul, li と一緒
ここ大事!!
# deleteを押すとYou sureというconfirmが出るのでそれの対処
# expectのブロック内にひとつ以上のexpectもしくはfindを入れないと、
# ダイアログが表示されてacceptされる前に次へ進んでしまうので注意が必要らしい
page.accept_confirm "You sure?"
# ここ!!!大事 これでOKの役割
expect(page).to have_content("Micropost deleted")
# 上の理由によりこれもいる
end.to change { Micropost.count }.by(-1)
# +@
# pageインスタンスにaccept_confirmとdismiss_confirmという
# ブラウザのダイアログ操作用メソッドが用意されていてる
# dismissに変えたところmicropostは減らなかった
visit user_path(@micropost.user)
expect(page).not_to have_link 'delete'
end
end
before do
@micropost = FactoryBot.create(:micropost)
@other_micropost = FactoryBot.create(:micropost)
# @user = FactoryBot.create(:user)
end
# ****今気づいたけどuserとmicropostはネストの関係じゃないんだ。だからuserのidとかいらない
# ここではそういう風にしてない ネストにしない理由はcurrent_userでuserの情報を持ってこれるから
it 'should redirect create when not logged in' do
expect do
# こことかuserのidいらない
end.to change { Micropost.count }.by(0)
expect(response).to redirect_to login_url
end
it 'should redirect destroy when not logged in' do
expect do
delete micropost_path(@micropost)
# こことか
end.to change { Micropost.count }.by(0)
expect(response).to redirect_to login_url
end
it "should redirect destroy for wrong micropost" do
log_in_as(@micropost.user)
expect do
delete micropost_path(@other_micropost)
# こことか
end.to change { Micropost.count }.by(0)
expect(response).to redirect_to root_path
end
end