###db/migrate/[timestamp]_add_admin_to_users.rb
db/migrate/[timestamp]_add_admin_to_users.rb
class AddAdminToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :admin, :boolean, default: false
end
end
rails db:migrate
###db/seeds.rb
db/seeds.rb
# メインのサンプルユーザーを1人作成する
User.create!(name: "Example User",
email: "example@railstutorial.org",
password: "foobar",
password_confirmation: "foobar",
admin: true)
# admin権限をつける
# 追加のユーザーをまとめて生成する
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
$ rails db:migrate:reset
$ rails db:seed
###app/views/users/_user.html.erb
app/views/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>
###app/controllers/users_controller.rb
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :logged_in_user, only: [:index, :edit, :update, :destroy]
before_action :correct_user, only: [:edit, :update]
before_action :admin_user, only: :destroy
def index
@users = User.paginate(page: params[:page])
end
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params) # 実装は終わっていないことに注意!
if @user.save
log_in @user
flash[:success] = "ようこそ自作アプリへ成功しました!"
redirect_to @user
else
render 'new'
end
end
def edit
@user = User.find(params[:id])
end
def update
@user = User.find(params[:id])
if @user.update(user_params)
flash[:success] = "Profile updated"
redirect_to @user
else
render 'edit'
end
end
def destroy
User.find(params[:id]).destroy
# データベースから探して削除する
flash[:success] = "User deleted"
redirect_to users_url
# わからない
end
private
def user_params
params.require(:user).permit(:name, :email, :password,
:password_confirmation)
end
def logged_in_user
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# 正しいユーザーかどうか確認
def correct_user
@user = User.find(params[:id])
redirect_to(root_url) unless @user == current_user
end
# 管理者かどうか確認
def admin_user
redirect_to(root_url) unless current_user.admin?
#管理者ではない時ホーム画面に移動する
end
end
###test/fixtures/users.yml
test/fixtures/users.yml
michael:
# テストデータ
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
admin: true
# 管理者
archer:
name: Sterling Archer
email: duchess@example.gov
password_digest: <%= User.digest('password') %>
lana:
name: Lana Kane
email: hands@example.gov
password_digest: <%= User.digest('password') %>
malory:
name: Malory Archer
email: boss@example.gov
password_digest: <%= User.digest('password') %>
<% 30.times do |n| %>
user_<%= n %>:
name: <%= "User #{n}" %>
email: <%= "user-#{n}@example.com" %>
password_digest: <%= User.digest('password') %>
<% end %>
###test/controllers/users_controller_test.rb
test/controllers/users_controller_test.rb
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
end
test "should get new" do
get signup_path
# users/newでgetリクエスト
assert_response :success
# リクエストを受けることができましたか?
end
test "should redirect edit when not logged in" do
# ログイン無しでは編集できないテスト
get edit_user_path(@user)
# 編集ページへの移動を要求
assert_not flash.empty?
# flashに中身はあるか?
assert_redirected_to login_url
# ログインページに自動的に移動させる
end
test "should redirect update when not logged in" do
# ログイン無しでは上書きできないテスト
patch user_path(@user), params: { user: { name: @user.name,
email: @user.email } }
# 情報を上書きする
assert_not flash.empty?
# flashに中身はあるか?
assert_redirected_to login_url
# 自動的にログインページに移動させる
end
test "should redirect destroy when not logged in" do
assert_no_difference 'User.count' do
# 削除されてデータベースを数えて減ってないか?
delete user_path(@user)
# ユーザーを削除する
end
assert_redirected_to login_url
# ログインページに自動的に移動しているか?
end
test "should redirect destroy when logged in as a non-admin" do
log_in_as(@other_user)
# ログインさせる
assert_no_difference 'User.count' do
# データベースの数に違いはないよね?
delete user_path(@user)
# 削除する
end
assert_redirected_to root_url
# ホーム画面に自動的に移動しているか?
end
end
###test/integration/users_index_test.rb
test/integration/users_index_test.rb
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'
# htmlにpaginateが入力されているか?
first_page_of_users = User.paginate(page: 1)
# 全ユーザーの1ページを代入
first_page_of_users.each do |user|
# 1ページ内から一つずつ取り出す
assert_select 'a[href=?]', user_path(user), text: user.name
# 名前を表示されているか?
unless user == @admin
# 管理者でなければ
assert_select 'a[href=?]', user_path(user), text: 'delete'
# 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
# ユーザーページへ移動
assert_select 'a', text: 'delete', count: 0
# deleteが表示されていないかを確認
end
end
ubuntu:~/environment/my_app (updating-users) $ rails t
Running via Spring preloader in process 8283
Run options: --seed 42332
# Running:
.....................E
Error:
UsersIndexTest#test_index_as_admin_including_pagination_and_delete_links:
NoMethodError: undefined method `email' for nil:NilClass
test/test_helper.rb:38:in `log_in_as'
test/integration/users_index_test.rb:11:in `block in <class:UsersIndexTest>'
rails test test/integration/users_index_test.rb:10
.........
Finished in 2.588285s, 11.9770 runs/s, 28.9767 assertions/s.
31 runs, 75 assertions, 0 failures, 1 errors, 0 skips
NoMethodError: undefined method `email' for nil:NilClass
###デプロイの後
$ rails test
$ git push heroku
$ heroku pg:reset DATABASE
アプリ名を入力する
$ heroku run rails db:migrate
$ heroku run rails db:seed