Hitsuji_monのブログ~ 村上春樹のあれ ~

文学好きな組み込み系エンジニア

【#100DaysOfCode】Day34 Railsチュートリアル 11章アカウントの有効化:解決

エラー解決した。よっしゃ。

Day34

Railsチュートリアル 11章 アカウントの有効化

発生したエラー

activation_tokenがうまく動かない

ERROR["test_account_activation", UserMailerTest, 0.3923750569999811]
 test_account_activation#UserMailerTest (0.39s)
NoMethodError:         NoMethodError: undefined method `activation_token=' for #<User:~~~~>
        Did you mean?  activation_digest=
                       activation_digest
            test/mailers/user_mailer_test.rb:7:in `block in <class:UserMailerTest>'

原因:app/models/user.rb の間違い。modelがテストと対応してなかったっぽい

間違い

# 間違っていたコード
class User < ApplicationRecord
  attr_accessor :remember_token
  before_save { self.email = email.downcase }
  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  has_secure_password
  validates :password, presence: true, length: { minimum: 6 }, allow_nil: true

  # 渡された文字列のハッシュ値を返す
  def User.digest(string)
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                  BCrypt::Engine.cost
    BCrypt::Password.create(string, cost: cost)
  end

  # ランダムなトークンを返す
  def User.new_token
    SecureRandom.urlsafe_base64
  end

  # 永続セッションのためにユーザーをデータベースに記憶する
  def remember
    self.remember_token = User.new_token
    update_attribute(:remember_digest, User.digest(remember_token))
  end

 # 渡されたトークンがダイジェストと一致したらtrueを返す
  def authenticated?(remember_token)
    return false if remember_digest.nil?
    BCrypt::Password.new(remember_digest).is_password?(remember_token)
  end

  # ユーザーのログイン情報を破棄する
  def forget
    update_attribute(:remember_digest, nil)
  end
end

正解

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 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                      format: { with: VALID_EMAIL_REGEX },  #6.21: メールフォーマットを正規表現で検証
                    uniqueness: { case_sensitive: false }   #6.27: メールアドレスの大文字小文字を無視した一意性の検証
  has_secure_password  #リスト 6.37
  #10.13: パスワードが空のままでも更新できるようにする
  validates :password, presence: true, length: { minimum: 6 }, allow_nil: true 

  # 渡された文字列のハッシュ値を返す
  def User.digest(string)  #8.21: fixture向けのdigestメソッドを追加
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                  BCrypt::Engine.cost
    BCrypt::Password.create(string, cost: cost)
  end

  # ランダムなトークンを返す
  def User.new_token # 9.2: トークン生成用メソッド
    SecureRandom.urlsafe_base64
  end

  # 永続セッションのためにユーザーをデータベースに記憶する
  def remember #9.3: rememberメソッドをUserモデルに追加
    self.remember_token = User.new_token
    update_attribute(:remember_digest, User.digest(remember_token))
  end

  # 渡されたトークンがダイジェストと一致したらtrueを返す
  def authenticated?(remember_token)  #9.6: authenticated?をUserモデルに追加
    return false if remember_digest.nil?  #9.19: authenticated?を更新して、ダイジェストが存在しない場合に対応
    BCrypt::Password.new(remember_digest).is_password?(remember_token)
  end

  # ユーザーのログイン情報を破棄する
  def forget #9.11: forgetメソッドをUserモデルに追加
    update_attribute(:remember_digest, nil)
  end
  private

  # メールアドレスをすべて小文字にする
  def downcase_email
    self.email.downcase!
  end

  # 有効化トークンとダイジェストを作成および代入する
  def create_activation_digest
    self.activation_token  = User.new_token
    self.activation_digest = User.digest(activation_token)
  end
end

やっと先進める。
理解度は半分くらいでとにかく進めるスタンスだけど、あまりにも理解していない感がある。

ま、実際にアプリ作り始めてから戻ってくればいいかな!