LoginSignup
0
0

More than 1 year has passed since last update.

railsチュートリアル第10章

Posted at

パーテーションを使いコードを短くする
テストは
こうなるべきであるということを定義すること
どう動くべきなのかを理解していなければならない。

 # 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のリンクが表示された。
予想が当たって嬉しかった。
これからも努力したい。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0