質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

Rails Tutorial 11章のテストが通りません

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 919

white4614

score 1

Rails Tutorialを学習しているプログラミング初心者です。

Rails Tutorial 11章の 11.2.4「ユーザーのcreateアクションの更新」で躓きました。

以下のようにユーザー登録にアカウント有効化を追加したのですが

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


以下のそれに対するテストが通らなくて困っています。

test "valid signup information" do
    get signup_path
    assert_difference 'User.count', 1 do
      post users_path, params: { user: { name:  "Example User",
                                         email: "user@example.com",
                                         password:              "password",
                                         password_confirmation: "password" } }
    end
    follow_redirect!
    #assert_template 'users/show'
    #assert is_logged_in?
end


エラーメッセージはこちらです

ERROR["test_valid_signup_information", UsersSignupTest, 1.0404080669395626]
 test_valid_signup_information#UsersSignupTest (1.04s)
ActionView::Template::Error:         ActionView::Template::Error: No route matches {:action=>"edit", :controller=>"account_activations", :email=>"user@example.com", :id=>nil}, possible unmatched constraints: [:id]
            app/views/user_mailer/account_activation.html.erb:9:in `_app_views_user_mailer_account_activation_html_erb__3563335001904869326_67139240'
            app/mailers/user_mailer.rb:5:in `account_activation'
            app/controllers/users_controller.rb:21:in `create'
            test/integration/users_signup_test.rb:21:in `block (2 levels) in <class:UsersSignupTest>'
            test/integration/users_signup_test.rb:20:in `block in <class:UsersSignupTest>'

試したこと

追加したUserMailer.account_activation(@user).deliver_now

のコードをコメントアウトしたらテストを通過するのでその辺がおかしいのかと思うのですがどこが違うのかわかりません。

エラーメッセージに書いてあるところを確認したのですが、間違ってるところが見当たりませんでした。

エラーメッセージの意味もよくわかってなくて申し訳ないのですが、ルーティングのどこかのidの値が入ってないってことででしょうか?

エラーメッセージに書いてあったファイルはこちらです↓

app/views/user_mailer/account_activation.html.erb:9:in `_app_views_user_mailer_account_activation_html_erb__3563335001904869326_67139240'

<h1>Sample App</h1>

<p>Hi <%= @user.name %>,</p>

<p>
  Welcome to the Sample App! Click on the link below to activate your account:
</p>

<%= link_to "Activate", edit_account_activation_url(@user.activation_token, email: @user.email) %>

 app/mailers/user_mailer.rb:5:in `account_activation'

class UserMailer < ApplicationMailer

  def account_activation(user)
    @user = user
    mail to: user.email, subject: "Account activation"
  end

  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.user_mailer.password_reset.subject
  #
  def password_reset
    @greeting = "Hi"

    mail to: "to@example.org"
  end
end


解決方法がわかる方、お教えいただけませんでしょうか?
宜しくお願いいたします。

※追記
こちらがconfig/routes.rbです

Rails.application.routes.draw do
  root 'static_pages#home'
  get '/help', to: 'static_pages#help'
  get '/about', to: 'static_pages#about'
  get '/contact', to: 'static_pages#contact'
  get '/signup', to: 'users#new'
  post '/signup',  to: 'users#create'
  get '/login', to: 'sessions#new'
  post '/login', to: 'sessions#create'
  delete '/logout', to: 'sessions#destroy'
  resources :users
  resources :account_activations, only: [:edit]
end
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • scivola

    2017/12/25 20:33

    No route matches とあるので,config/routes.rb も見せてもらえますか。

    キャンセル

  • white4614

    2017/12/25 21:05

    config/routes.rbを追記致しました

    キャンセル

回答 3

checkベストアンサー

+2

エラーメッセージの核心部分

ActionView::Template::Error: No route matches {:action=>"edit", :controller=>"account_activations", :email=>"user@example.com", :id=>nil}, possible unmatched constraints: [:id]

に注目してみましょう。
:id=>nil とありますね。
与えられるべき :id が与えられていないので,該当するルーティング定義が見つけられなかったようです。

で,そういう URL を生成したのはメールのテンプレートの中の

edit_account_activation_url(@user.activation_token, email: @user.email)

という記述です。これが怪しいですね。

@user.activation_token が nil になっているような気がします。

activation_token は users テーブルのカラムではなくて,attr_accessor で User モデルに持たせたものですよね。
どこかで @user.activation_token =  って代入してやるはずなのではないでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/27 14:14

    回答ありがとうございます!
    Telatailを使うのが初めてだったので、質問の仕方もよく分からず、Telatailの利用者の方々に内容が通じるか不安だったのですが、こんなに丁寧にわかりやすく回答いただけて本当に感謝しています。
    お忙しいところ、時間を割いていただきありがとうございました!

    キャンセル

+1

私もわかりませんが、11.2.3まではうまく行っていたのでしょうか?
GitHubにチュートリアルを完成した状態のコードが載っているので、そちらを参考にdiffコマンドなども駆使して、見比べてみてはいかがでしょうか。
https://github.com/yasslab/sample_apps

追記:コードが全部合っていても、もしかしたら前に作ったダミーデータに抜けがあったりするかもしれないので、rails dbconsoleから調べてみましょう。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/12/27 14:17

    ご回答ありがとうございます!
    diffコマンドというものがあるんですね!これは便利ですね!
    完成したコードと一緒に利用したいと思います!

    キャンセル

0

scivolaさんのご指摘の通り、acctivation_tokenに値が代入されていませんでした。
before_createで値を代入するメソッドを呼び出すのを見落としていたようです。

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 }, uniqueness: { case_sensitive: false }
  has_secure_password
  validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
  class << self
    def digest(string)
      cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
                                                    BCrypt::Engine.cost
      BCrypt::Password.create(string, cost: cost)
    end

    def new_token
      SecureRandom.urlsafe_base64
    end
  end

  def remember
    self.remember_token = User.new_token
    update_attribute(:remember_digest, User.digest(remember_token))
  end

  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

  private

  def downcase_email
    email.downcase!
  end
#↓これがbefore_createされていませんでした。  
  def create_activation_digest
    self.activation_token = User.new_token
    self.activation_digest = User.digest(activation_token)
  end
end


結果、テストをパスすることができました。
皆さんご回答ありがとうございました。本当に助かりました!

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る