パーテーションを使いコードを短くする
テストは
こうなるべきであるということを定義すること
どう動くべきなのかを理解していなければならない。
# GET /users/:id/edit ユーザ情報を更新するとき
def edit
@user = User.find(params[:id])
# デフォルトでは app/views/users/edit.html.erbにレンダリングされる
# (ページに飛ぶ)
# しかしまだedit.html.erbがないので作る
end
def update
@user = User.find(params[:id])
if @user.update(user_params)
# 更新に成功した場合を扱う。
else
# @user.error <=== ここにデータが入っている
render 'edit'
# じゃなかったらeditページに飛ぶ
end
end
test "successful edit" do
get edit_user_path(@user)
# edit_user_path(@user)を表示する
assert_template 'users/edit'
# editページが表示されるかをテストする
name = "Foo Bar"
# nameを定義する
email = "foo@bar.com"
patch user_path(@user), params: { user: { name: name,
email: email,
password: "",
password_confirmation: "" } }
# 不十分なパスワードを置き換えする
assert_not flash.empty?
# わからん
# 空じゃないよね?
assert_redirected_to @user
# わからん
# @userがどうなっているかを検証する
@user.reload
# @userを再取得
assert_equal name, @user.name
# 定義したnameと@userのnameが等しいかテストする
assert_equal email, @user.email
end
リダイレクトとは
あるページから別のページに転送すること
サンプルユーザーを生成するRubyスクリプト
# メインのサンプルユーザーを1人作成する
User.create!(name: "Example User",
email: "example@railstutorial.org",
password: "foobar",
password_confirmation: "foobar")
# 追加のユーザーをまとめて生成する
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
ユーザーが無効な場合にfalseを返すのではなく例外を発生させる
$ rails db:migrate:reset
$ rails db:seed
上でリセットし、100人のデータができる。
ページネーション
1つのページに一度に30人だけユーザーを表示する
ユーザー全体を表示するのは多すぎるから
<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>
<ul class="users">
<% @users.each do |user| %>
<li>
<%= gravatar_for user, size: 50 %>
<%= link_to user.name, user %>
</li>
<% end %>
</ul>
<%= will_paginate %>`
def index
@users = User.paginate(page: params[:page])
end
ユーザーの削除
そのために
ユーザー削除の権限を持つadminクラスを作成
rails generate migration add_admin_to_users admin:boolean
webページにオブジェクトを晒すことは攻撃される危険がある。
Strong Parametersを使って対策をする。
Strong Parametersについてはまだ理解していない。
destroyアクション
destroyアクションへのリンクを追加
管理ユーザーへのアクセスを制限します
All usersにdeleteが表示される
<li>
<%= gravatar_for user, size: 50 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
<!--.adminで管理者であるかを確認かつwebのユーザーであるならば-->
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<!--deleteのリンク、delete(削除)を行うことができる-->
<!--user_path(user) => DELETE /users/:id => destroy -->
<!--userでidをもとにとれ出されDELETEで消される-->
<% end %>
</li>
destroyアクションの内容
def destroy
# destroyアクション
User.find(params[:id]).destroy
# 任意のidのユーザーを削除する
flash[:success] = "User deleted"
# 削除のメッセージを表示する
# [:success]なので緑
redirect_to users_url
# users_urlのページに移動する
end
まだこの状態では誰でも削除をすることができるらしいので
自分が管理者であるかを確認する必要がある。
users_controller
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
# ログインしていないユーザーが保護されたページに
# アクセスしようとした際のケースについて対処
# ログインしていない場合に
# ログインページにリダイレクトさせるヘルパーメソッド
# 何らかの処理が実行される直前に特定のメソッドを実行する
# :editと:updateアクションだけにこのフィルタが適用される
# :edit,:updateアクションが呼び出されたらlogged_in_userを行う
# メソッドを呼び出すときは基本シンボルで呼び出す
# メソッド名を引数に渡すときはシンボルで呼ぶ
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
# 管理者だけが実行させる [:destroy]でも書いていいい。
.
.
.
# 管理者かどうか確認
def admin_user
redirect_to(root_url) unless current_user.admin?
# current_userがadminでなければroot_urlのページに飛ぶ
end
end
テスト用のユーザに管理者権限を与える
michael:
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
admin: true
.
.
.
管理者権限を制御を行う
require 'test_helper'
class UsersIndexTest < ActionDispatch::IntegrationTest
def setup
@admin = users(:michael)
@non_admin = users(:archer)
end
test "index as admin including pagination and delete links" do
log_in_as(@admin)
get users_path
assert_template 'users/index'
assert_select 'div.pagination'
first_page_of_users = User.paginate(page: 1)
first_page_of_users.each do |user|
assert_select 'a[href=?]', user_path(user), text: user.name
unless user == @admin
assert_select 'a[href=?]', user_path(user), text: 'delete'
end
end
assert_difference 'User.count', -1 do
delete user_path(@non_admin)
end
end
test "index as non-admin" do
log_in_as(@non_admin)
# 管理者以外のユーザーがログインして
get users_path
# users_pathにアクセスする
assert_select 'a', text: 'delete', count: 0
# deleteのリンクは表示されていない(0回)よね?,
end
end
ためになった話
テストとはこれはこうあるべきと定義するもの
何かを作りたいと思ったら
テストを作り、ある程度ルールを決めておくことを学んだ。
頑張りたい。
困ったこと
deleteのリンクが表示されると思ったが
表示されなかった。 困った。
テキストではJavaScriptの云々と書いてあったが、そう言うような操作をしていないと思った。
なので
自分がログインしているのが管理者ではないアカウントでログインしているのかと予想を立てた。
そのためにコードにemailとpasswordを入力してみたら
daleteのリンクが表示された。
予想が当たって嬉しかった。
これからも努力したい。