Railsチュートリアル10章 

Railsチュートリアル10章について大事だと思ったことをメモっときます。

テストコードはRspecを使っています。

 

フレンドリーフォワーティング

ログイン前にそのページに行こうとしていたら、ログインした後は行こうとしたページになっていること。

Sessionを使ってurlを保存してあげる。

ログインする前にurlをsessionに保存(ログイン前、ページに行こうとした時)

ログインした後にそのurlにリダイレクト。行こうとしていたページがない場合はそのまま指定されたページ(デフォルト)。デフォルトのページは引数で渡されている。

sessions_helper.rb


# 記憶したURL(もしくはデフォルト値)にリダイレクト
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end

# アクセスしようとしたURLを覚えておく こっちが先に行われる!!
def store_location
session[:forwarding_url] = request.original_url if request.get?
end

url保存はusersコントローラーのbeforeアクション

def logged_in_user
unless logged_in?
store_location ここ!!
flash[:danger] = "Please log in."
redirect_to login_url
end
end

保存されたurlに行くのはsessionsコントローラーのcreateアクション(ログインする時)

def create
user = User.find_by(email: params[:session][:email].downcase)
if user&.authenticate(params[:session][:password])
# 元々はこう user && user.authenticate(params[:session][:password])
# このauthenticateはhas_secure_passwordが持つ特性なので定義しなくても使える。
# 一方remember_tokenとかはhas_secure_passwordとは関係ないのでauthenticateメソッドを定義する必要がある
log_in user
params[:session][:remember_me] == '1' ? remember(user) : forget(user)
redirect_back_or user ここ!!
           defaultがuserにあたる。 つまりはuser_path showにあたる。
 
 
else
 
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end

---------------------------------------------------------------------------------------

pagination ページ分割

gemを入れる。

gem 'will_paginate', '3.1.8'
gem 'bootstrap-will_paginate', '1.0.0' これはbootstrapのcssに対応するようにしている

 

ページ分割にはwill_paginateを使う。

usersビューのコードの中から@usersを自動で見つけていき他のページにアクセスするページネーションリンクを作成。

<%= will_paginate %> ここ!!
これを書くだけでページネーションリンク
1 2 3 NEXT のようなリンクを作れる。デフォルトで1ページに30こ

<ul class="users">
<% @users.each do |user| %>
<li>
<%= gravatar_for user, size: 50 %>
<%= link_to user.name, user %>
</li>
<% end %>
</ul>

<%= will_paginate %> ここ!!
2つ使っているのは上と下にそれぞれ置きたいから。1つでも問題ない。

 

userコントローラー

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

 

リファクタリング 上の記述をリファクタリングします。

users/index.html.erb

<% provide(:title, 'All users') %>
<h1>All users</h1>

<%= will_paginate %>

<ul class="users">
<%= render @users %> ここ!!
こう書くことでまず_user.html.erbを呼び出す。
    そして@usersに含まれているやつを1つ1つ呼び出す。
    つまりeachなしでもそれぞれ呼び出すことができる。
</ul>

<%= will_paginate %>

users/_user.html.erb

<li>
<%= gravatar_for user, size: 50 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
</li>

 

---------------------------------------------------------------------------------------

admin 管理ユーザーになる

まずはmigration

class AddAdminToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :admin, :boolean, default: false
# これは無くてもadminがnilになるのでいいらしい。
# ただ見た人にわかりやすくしている
end
end

このmigrationでadminかどうかを調べるadmin?メソッドも使えるようになる

 

---------------------------------------------------------------------------------------

ユーザーを一気に大量に作る方法

db/seedsに書く。

# メインのサンプルユーザーを1人作成する
User.create!(name: "Example User",
email: "example@railstutorial.org",
password: "foobar",
password_confirmation: "foobar",
admin: true)

# 追加のユーザーをまとめて生成する ここ!!
99.times do |n|
name = Faker::Name.name
email = "example-#{n+1}@railstutorial.org"
password = "password"
User.create!(name: name,
email: email,
password: password,
password_confirmation: password)
end

 

ちなみにテストコードでユーザーを大量に追加する方法は

RSpec.describe "Index 大量のuser", type: :system do
before do
@user = FactoryBot.create(:user)
@other_user= FactoryBot.create(:user)
@users=FactoryBot.create_list(:user, 100) ここ!! create_listでユーザーを大量に作成
                      今回だと100
@users=は別に必要ないと思う。
end

 

---------------------------------------------------------------------------------------

テストコード

テストコードはsystem,requestそれぞれに書いたので順番通りになってないです。

require 'rails_helper'
 
RSpec.describe "Users", type: :system do
before do
@user = FactoryBot.create(:user)
@other_user= FactoryBot.create(:user)
 
end
it "unsuccessful edit" do
log_in(@user)
visit edit_user_path(@user)
fill_in 'Name', with:"AAA"
fill_in 'Email', with:"aaa@111.com"
fill_in 'Password', with: "abcdef"
fill_in 'Password confirmation', with: "fbaxfe"
find('input[name="commit"]').click
expect(has_css?('.alert-danger')).to be_truthy
 
end

it "successful edit" do
log_in(@user)
visit edit_user_path(@user)
fill_in 'Name', with:"AAA"
fill_in 'Email', with:"aaa@111.com"
fill_in 'Password', with: "abcdef"
fill_in 'Password confirmation', with: "abcdef"
find('input[name="commit"]').click
expect(current_path).to eq(user_path(@user))
expect(page).to have_content'Profile updated'

@user.reload
expect(@user.name).to eq("AAA")
expect(@user.email).to eq("aaa@111.com")

end

it "should redirect edit when not logged in" do
visit edit_user_path(@user)
expect(current_path).to eq(login_path)
end

# ログインしていないupdateのテストはrequest specで書く(下)
it 'should redirect edit when logged in as wrong user' do
log_in(@user)
visit edit_user_path(@other_user)
expect(current_path).to eq(root_path)


end

it "successful edit with friendly forwarding" do

visit edit_user_path(@user)
log_in(@user)
expect(current_path).to eq(edit_user_path(@user))
fill_in 'Name', with:"BBB"
fill_in 'Email', with:"abc@111.com"
find('input[name="commit"]').click
expect(current_path).to eq(user_path(@user))
expect(page).to have_content'Profile updated'
end

it "should redirect index when not logged in" do
visit users_path
expect(current_path).to eq(login_path)
end


end


RSpec.describe "Index 大量のuser", type: :system do
before do
@user = FactoryBot.create(:user)
@other_user= FactoryBot.create(:user)
@users=FactoryBot.create_list(:user, 100)
end

 
it 'index including pagination' do
log_in(@user)
visit users_path
User.paginate(page: 1).each do |user|    ページネーションはこうやってやる
expect(page).to have_link href: user_path(user)
expect(page).to have_content(user.name)
end do~endで書かれてる
end


end






RSpec.describe "Users", type: :request do
before do
@user = FactoryBot.create(:user)
@other_user= FactoryBot.create(:user)
end

it 'should redirect update when not logged in' do
patch user_path(@user), params: { user: { name: @user.name,
email: @user.email } }
expect(response).to redirect_to login_path
end

it "should redirect update when logged in as wrong user" do
log_in_as(@other_user)
patch user_path(@user), params: { user: { name: @user.name,
email: @user.email } }
expect(response).to redirect_to root_path


end

it 'should not allow the admin attribute to be edited via the web' do
log_in_as(@other_user)
patch user_path(@other_user), params: {
user: { password: "password",
password_confirmation: "password",
admin: true } }
expect(@other_user.admin?).to be_falsy
 

end


end

RSpec.describe "Admin", type: :request do
before do
@user = FactoryBot.create(:user,:admin)
@other_user= FactoryBot.create(:user)
end

it "should redirect destroy when not logged in" do
 
expect do
delete user_path(@other_user)
end.to change { User.count }.by(0)
expect(response).to redirect_to login_url
end

it 'should redirect destroy when logged in as a non-admin' do
log_in_as(@other_user)
 
expect do              下に説明書いた
delete user_path(@user)
end.to change { User.count }.by(0)
 
expect(response).to redirect_to root_path
end


it "index as admin including pagination and delete links" do
log_in_as(@user)
 
expect do ここ!! request specでも expect do~ end.to~は使える。
          今回はdelete_pathに行くとUserのカウントが1減るよう書いてる
delete user_path(@other_user)
end.to change { User.count }.by(-1)
 
expect(response).to redirect_to users_path
end



end

 




 

以上で10章終わりです!