Ошибка регистрации пользователя в учебнике М.Хартла по Rails

Я следил за учебником М. Хартла по Rails и столкнулся с проблемой. Когда я перешел из главы 10, все по коду работало, и мой набор тестов проходил. В главе 11 все, что я до сих пор делал, - это создание новой ветви. Ни один из моих файлов не был изменен. Тем не менее, так или иначе, мой набор тестов сейчас не работает. Еще более странным является то, что он не терпит неудачу в 100% случаев. Иногда это проходит, но в большинстве случаев происходит сбой (если я запускаю его снова и снова без изменения какого-либо кода). Соответствующий код и сообщение об ошибке ниже. Любая помощь будет принята с благодарностью. Спасибо

Ошибка:

FAIL["test_valid_signup_information_with_account_activation", UsersSignupTest, 3.902866843]
test_valid_signup_information_with_account_activation#UsersSignupTest (3.90s)
    Expected: 1
      Actual: 2
    test/integration/users_signup_test.rb:29:in `block in <class:UsersSignupTest>'

user_signup_test.rb

require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do 
      post users_path, user: {name: "Stevan",
                              email: "foo@invalid",
                              password: "foo",
                              password_confirmation: "bar"}
    end
    assert_template 'users/new'
    assert_select 'div#error_explanation'
    assert_select 'div.alert-danger'
  end

  test "valid signup information with account activation" do
    get signup_path
    #name = "Example User"
    #email = "user@example.com"
    #password = "password"
    assert_difference 'User.count', 1 do
      post users_path, user:{name: "Example User",
                             email: "user@example.com",
                             password:              "password",
                             password_confirmation: "password"}
    end
    assert_equal 1, ActionMailer::Base.deliveries.size
    user = assigns(:user)
    assert_not user.activated?
    # Try to log in before activation.
    log_in_as(user)
    assert_not is_logged_in?
    # Invalid activation token
    get edit_account_activation_path("invalid token")
    assert_not is_logged_in?
    # Valid token, wrong email
    get edit_account_activation_path(user.activation_token, email: 'wrong')
    assert_not is_logged_in?
    # Valid activation token
    get edit_account_activation_path(user.activation_token, email: user.email)
    assert user.reload.activated?
    follow_redirect!
    assert_template 'users/show'
    assert is_logged_in?
  end
end

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 new
    @user = User.new
  end

  def show
    @user = User.find(params[:id])
  end

  def create
    @user = User.new(user_params)  
    if @user.save
      #UserMailer.account_activation(@user).deliver #deliver_now
      @user.send_activation_email
      flash[:info] = "Please check your email to activate your account"
      redirect_to root_url
    else
      render 'new'
    end
  end

  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "User deleted"
    redirect_to users_url
  end

  def edit
    #@user = User.find(params[:id]) no longer needed as we have implemented correct_user
  end

  def update
    #@user = User.find(params[:id]) no longer needed as we have implemented correct_user
    if @user.update_attributes(user_params)
      flash[:success] = 'Profile updated'
      redirect_to @user
    else
      render 'edit'
    end
  end

  private 

    def user_params
      params.require(:user).permit(:name, :email, :password, :password_confirmation) #haven't permit admin -> not editable in the browser
    end

    #before filters

    #confirms a logged-in user.
    def logged_in_user
      unless logged_in?
        store_location
        flash[:danger] = "Please log in."
        redirect_to login_url
      end
    end

    #confirms the currect user is the user currently logged in
    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless current_user?(@user) #@user==current_user refactored
    end

    #confirms as admin user
    def admin_user
      redirect_to(root_url) unless current_user.admin?
    end
end

user.rb

class User < ActiveRecord::Base
  attr_accessor :remember_token, :activation_token, :reset_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]{2,4}+\z/i
  validates(:email, presence:true, format: {with: VALID_EMAIL_REGEX}, uniqueness: {case_sensitive: false})

  has_secure_password
  validates :password, length: {minimum: 6}, allow_blank: true

  #returns the hash digest of the given string
  def User.digest(string) #more idimatically correct to define as self.digest
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                  BCrypt::Engine.cost
    BCrypt::Password.create(string, cost: cost)
  end

  #returns a random token
  def User.new_token #more idiomatically correct to define as self.new_token
    SecureRandom.urlsafe_base64
  end

  #remembers a user in the database for use in persistent sessions
  def remember 
    self.remember_token = User.new_token
    update_attribute(:remember_digest, User.digest(remember_token))
  end

  # Returns true if the given token matches the digest.
  def authenticated?(attribute, token)
    digest = send("#{attribute}_digest")
    return false if digest.nil?
    BCrypt::Password.new(digest).is_password?(token)
  end

  #forgets a user
  def forget
    update_attribute(:remember_digest, nil)
  end

  #activates an account
  def activate 
    update_attribute(:activated,    true)
    update_attribute(:activated_at, Time.zone.now)
  end

  #send activation email
  def send_activation_email
    UserMailer.account_activation(self).deliver
  end

  #sets the password reset attrobutes
  def create_reset_digest
    self.reset_token = User.new_token
    update_attribute(:reset_digest, User.digest(reset_token))
    update_attribute(:reset_sent_at, Time.zone.now)
  end

  #sends password reset email
  def send_password_reset_email
    UserMailer.password_reset(self).deliver
  end

  #Returns true if password has expired
  def password_reset_expired?
    reset_sent_at < 2.hours.ago
  end

  private
    #converts email all to lower case
    def downcase_email
      self.email = email.downcase
    end

    #creates and assigns activation token and digest
    def create_activation_digest
      self.activation_token = User.new_token
      self.activation_digest = User.digest(activation_token)
    end
end

Gemfile

source 'https://rubygems.org'
ruby '2.1.1'

gem 'rails',                  '4.2.0.beta1'
gem 'bcrypt',                 '3.1.7'
gem 'faker',                  '1.4.2'
gem 'will_paginate',          '3.0.7'
gem 'bootstrap-will_paginate','0.0.10'
gem 'byebug',                 '3.5.1'
gem 'bootstrap-sass',         '3.2.0.0'
gem 'sass-rails',             '5.0.0.beta1'
gem 'uglifier',               '2.5.1'
gem 'coffee-rails',           '4.0.1'
gem 'jquery-rails',           '3.1.1'
gem 'turbolinks',             '2.3.0'
gem 'jbuilder',               '2.1.3'
gem 'sdoc',                   '0.4.0', group: :doc

group :test do
  gem 'minitest-reporters',   '1.0.5'
  gem 'mini_backtrace',       '0.1.3'
  gem 'guard-minitest',       '2.3.1'
end

group :development do
  gem 'sqlite3',              '1.3.9'
  gem 'spring',               '1.1.3'
end

group :production do
  gem 'pg',                   '0.17.1'
  gem 'rails_12factor',       '0.0.2'
  gem 'unicorn',              '4.8.3'
end

2 ответа

Решение

В вашем коде отсутствует setup метод, определенный в листинге 10.29.

Попробуйте добавить следующее перед подключением ко всем спецификациям, касающимся ActionMailer

before { ActionMailer::Base.deliveries = [] }

Похоже, что другие спецификации также отправлять электронные письма. Результаты варьируются из-за произвольного порядка спецификаций.

Другие вопросы по тегам