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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

2870閲覧

rails tutorial 12章 テンプレートエラー に苦しめられております。

kntarohh

総合スコア11

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2019/07/20 14:00

編集2019/07/21 12:36

前提・実現したいこと

初質問です。言葉足らずなところがあるかも知れませんがご協力いただけますと幸いです。
現在rails tutorialの12章に取り組んでおります。

パスワードを再設定する為のメールを送るべく、パスワードリセットのリソース作成、Userモデルにパスワード再設定用のトークンとそれに対応するダイジェストを追加し、再設定メールのテンプレートを作成などをしました。

順調に進んでるかと思いきや、以下のエラーメッセージが解消できずに半日戦っております。
前章ではエラーが出なかったので恐らく本章でやらかしたかと思われます。

発生している問題・エラーメッセージ

Error: UserMailerTest#test_password_reset: ActionView::Template::Error: No route matches {:action=>"edit", :controller=>"account_activations", :email=>"michael@example.com", :id=>nil}, possible unmatched constraints: [:id] app/views/layouts/mailer.html.erb:9:in `_app_views_layouts_mailer_html_erb___4506527162881960628_72659080' app/mailers/user_mailer.rb:13:in `password_reset' test/mailers/user_mailer_test.rb:21:in `block in <class:UserMailerTest>'

実施したテスト("password_reset"のテストを追加したところからエラーが出始めました。コメントアウトするとパスします。)

require 'test_helper' class UserMailerTest < ActionMailer::TestCase test "account_activation" do user = users(:michael) user.activation_token = User.new_token mail = UserMailer.account_activation(user) assert_equal "Account activation", mail.subject assert_equal ["michael@example.com"], mail.to assert_equal ["noreply@example.com"], mail.from assert_match user.name, mail.body.encoded assert_match user.activation_token, mail.body.encoded assert_match CGI.escape(user.email), mail.body.encoded end test "password_reset" do user = users(:michael) user.reset_token = User.new_token mail = UserMailer.password_reset(user) assert_equal "Password reset", mail.subject assert_equal [user.email], mail.to assert_equal ["noreply@example.com"], mail.from assert_match user.reset_token, mail.body.encoded assert_match CGI.escape(user.email), mail.body.encoded end end

★app/views/layouts/mailer.html.erb

<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

class UserMailer < ApplicationMailer def account_activation(user) @user = user mail to: user.email end def password_reset(user) @user = user mail to: user.email, subject: "Password reset" end end

★app/models/user.rb

class User < ApplicationRecord 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]+\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 self.digest(string) cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost BCrypt::Password.create(string, cost: cost) end # ランダムなトークンを返す def self.new_token SecureRandom.urlsafe_base64 end <略> # 渡されたトークンがダイジェストと一致したらtrueを返す def authenticated?(attribute, token) digest = send("#{attribute}_digest") return false if digest.nil? BCrypt::Password.new(digest).is_password?(token) end # アカウントを有効にする def activate update_columns(activated: true, activated_at: Time.zone.now) end # 有効化用のメールを送信する def send_activation_email UserMailer.account_activation(self).deliver_now end # パスワード再設定の属性を設定する 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 # パスワード再設定のメールを送信する def send_password_reset_email UserMailer.password_reset(self).deliver_now end private # メールアドレスをすべて小文字にする def downcase_email email.downcase! end # 有効化トークンとダイジェストを作成および代入する def create_activation_digest self.activation_token = User.new_token self.activation_digest = User.digest(self.activation_token) end end

★config/routes.rb

Rails.application.routes.draw do get 'password_resets/new' get 'password_resets/edit' get 'sessions/new' 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] resources :password_resets, only: [:new, :create, :edit, :update] end

試したこと

activation_token が nil であることが原因であると思うのですが、"account_activation"のテストはパスするので、user.rb の create_activation_digest が実行されていないとしたら原因がわかりません。。

また、メールのプレビューを見ようとブラウザで http://<ホスト名>/rails/mailers/user_mailer/password_reset にアクセスすると本件と同様のエラーが確認できました。

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

winterboum

2019/07/20 20:18

routees.rbも載せて下さい
winterboum

2019/07/21 11:40

app/mailers/user_mailer.rb が有るかと思ったら、これ中身違いますね、viewのでは。 app/mailers/user_mailer.rbを。
guest

回答1

0

ベストアンサー

  1. resources :account_activations, only: [:edit]

に対応して
2) edit_account_activation_url(@user.activation_token, email: @user.email)
がつかわれています。
が、
1)の様に定義した場合定義されるurlは /account_activations/:id/edit と :id というパラメータを必要とするものです。
しかし2)にはidが定義されていません。
AccountActibationsController#edit が提示されていないんで予想ですが、Userから該当するレコードを取り出すのではないでしょうか。
すると
edit_account_activation_url(@user)としてください。
email、activation_token は #editの方で、user=User.find(parms[:id])してそのuserから採ります。
ただ、その場合 user.reset_token = User.new_token のあとsaveが必要です。実際の運用では、tokenをsaveしておく必要が有るはずですからそれで良いかと思います。

投稿2019/07/21 13:04

winterboum

総合スコア23567

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kntarohh

2019/07/22 12:44

ご回答いただき誠に有難うございます。 app/views/user_mailer/account_acctivation.html.erb に書くべき内容を app/views/layouts/mailer.html.erb に書いてしまっていたようです。 上記ファイルの修正で無事テストはパスしましたが、チュートリアル完走後、 ご回答いただいた内容につきましてもトライしてみようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問