0
0

More than 1 year has passed since last update.

railsチュートリアル第11章 アカウントを有効化する

Posted at

アカウントを有効化する

今度はAccountActivationsコントローラのeditアクションを書いていきましょう。
AccountActivationsコントローラからUserモデルにコードを移していく作業(リファクタリング)にも取り掛かっていきます。

authenticated?メソッドの抽象化

$ rails console
>> a = [1, 2, 3]
>> a.length
=> 3
>> a.send(:length)
=> 3
>> a.send("length")
=> 3

シンボルも文字列もlengthメソッドなので等価になる。

>> user.activation_digest
=> "$2a$12$x4xVHmtrDFjVPFFWav31UebLY8r9sdT8ImzSXGSrnqtQBKHyw8Ff."
>> user.send(:activation_digest)
=> "$2a$12$x4xVHmtrDFjVPFFWav31UebLY8r9sdT8ImzSXGSrnqtQBKHyw8Ff."
>> user.send("activation_digest")
=> "$2a$12$x4xVHmtrDFjVPFFWav31UebLY8r9sdT8ImzSXGSrnqtQBKHyw8Ff."
>> attribute = :activation
=> :activation
# Rubyではシンボルを使う方が一般的

>> user.send("#{attribute}_digest")
=> "$2a$12$x4xVHmtrDFjVPFFWav31UebLY8r9sdT8ImzSXGSrnqtQBKHyw8Ff."
class User < ApplicationRecord
  attr_accessor :remember_token, :activation_token
  before_save   :downcase_email
  before_create :create_activation_digest
  # トークンとそれに対応するダイジェストを割り当てる
  validates :name,  presence: true, length: { maximum: 50 }
  #属性はname,属性の存在を検証、 最大50字まで
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
  #最大255字まで
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: true
                    #???
  has_secure_password
  #セキュアなパスワードの実装
  # オブジェクト生成時に存在性を検証
  # 空のパスワード(nil)が新規ユーザー登録時に有効になることはありません
  validates :password, presence: true, length: { minimum: 5 }, allow_nil: true
  # パスワードのバリデーションの設定
  # 最低は六文字
  # パスワードのバリデーションに対して、空だったときの例外処理を加える

  def self.digest(string)
  # 渡された文字列のハッシュ値を返す
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                  BCrypt::Engine.cost
.
.
.
  # 渡されたトークンがダイジェストと一致したらtrueを返す
  def authenticated?
  # アカウント有効化のダイジェストと、
  #   渡されたトークンが一致するかどうかをチェック
  # 記憶トークン用なので今は正常に動作しません。
    digest = send("#{attribute}_digest")
    # rememberの部分を変数にして、状況に応じて呼び出すメソッドを切り替える
    return false if digest.nil?
    BCrypt::Password.new(digest).is_password?(token)
  end
.
.
.
end
テスト
ubuntu:~/environment/sample_app (account-activation) $ rails t
Running via Spring preloader in process 6707
Started with run options --seed 3172

ERROR["test_current_user_returns_nil_when_remember_digest_is_wrong", #<Minitest::Reporters::Suite:0x0000563b1d765260 @name="SessionsHelperTest">, 2.9934008690001974]
 test_current_user_returns_nil_when_remember_digest_is_wrong#SessionsHelperTest (2.99s)
ArgumentError:         ArgumentError: wrong number of arguments (given 0, expected 1)
            app/models/user.rb:51:in `authenticated?'
            app/helpers/sessions_helper.rb:31:in `current_user'
            test/helpers/sessions_helper_test.rb:24:in `block in <class:SessionsHelperTest>'

ERROR["test_current_user_returns_right_user_when_session_is_nil", #<Minitest::Reporters::Suite:0x0000563b1d778130 @name="SessionsHelperTest">, 3.0089105970000674]
 test_current_user_returns_right_user_when_session_is_nil#SessionsHelperTest (3.01s)
ArgumentError:         ArgumentError: wrong number of arguments (given 0, expected 1)
            app/models/user.rb:51:in `authenticated?'
            app/helpers/sessions_helper.rb:31:in `current_user'
            test/helpers/sessions_helper_test.rb:14:in `block in <class:SessionsHelperTest>'

ERROR["test_authenticated?_should_return_false_for_a_user_with_nil_digest", #<Minitest::Reporters::Suite:0x0000563b1c85c188 @name="UserTest">, 3.3450159330000133]
 test_authenticated?_should_return_false_for_a_user_with_nil_digest#UserTest (3.35s)
ArgumentError:         ArgumentError: wrong number of arguments (given 0, expected 1)
            app/models/user.rb:51:in `authenticated?'
            test/models/user_test.rb:88:in `block in <class:UserTest>'

  44/44: [============================] 100% Time: 00:00:03, Time: 00:00:03

Finished in 3.66714s
44 tests, 171 assertions, 0 failures, 3 errors, 0 skips

current_user内の抽象化したauthenticated?メソッド

app/helpers/sessions_helper.rb

module SessionsHelper
.
.
.
  def current_user
    if (user_id = session[:user_id])
    # ログイン中のidを代入する
    # 永続セッション(ログイン中)にするため
      @current_user ||= User.find_by(id: user_id)
      # カレントユーザーまたは検索結果があったものを代入する
    elsif (user_id = cookies.signed[:user_id])
    # 
      user = User.find_by(id: user_id)
      # idでユーザーを探す
      if user && user.authenticated?(:remember, cookies[:remember_token])
        # ユーザーが有効であり、記憶トークンも認証されたら
        log_in user
        # ログインする
        @current_user = user
        # カレントユーザーに代入するかな
      end
    end
  end
.
.
.
end

Userテスト内の抽象化したauthenticated?メソッド

test/models/user_test.rb

require 'test_helper'

class UserTest < ActiveSupport::TestCase
  def setup
    @user = User.new(name: "Example User", email: "user@example.com",
                     password: "foobar", password_confirmation: "foobar")
  end
.
.
.  
  test "authenticated? should return false for a user with nil digest" do
    assert_not @user.authenticated?(:remember, '')
    # 空かどうか?
  end
end
テスト
ubuntu:~/environment/sample_app (account-activation) $ rails t
Running via Spring preloader in process 7935
Started with run options --seed 61348

  44/44: [============================] 100% Time: 00:00:02, Time: 00:00:02

Finished in 2.30102s
44 tests, 175 assertions, 0 failures, 0 errors, 0 skips

演習

1.
コンソール内で新しいユーザーを作成してみてください。新しいユーザーの記憶トークンと有効化トークンはどのような値になっているでしょうか? また、各トークンに対応するダイジェストの値はどうなっているでしょうか?

#<User id: 103, name: "d", email: "abc2@def.com", created_at: "2021-10-18 07:01:26", updated_at: "2021-10-18 07:01:26", password_digest: [FILTERED], remember_digest: nil, admin: false, activation_digest: "$2a$12$IIiEogZPhOFemhstZ6kEmuboRLSRHUToOlp/ffbUivv...", activated: false, activated_at: nil>

2.
リスト 11.26で抽象化したauthenticated?メソッドを使って、先ほどの各トークン/ダイジェストの組み合わせで認証が成功することを確認してみましょう

わからなかった。

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