###gitをチェックアウトをする
git checkout -b password-reset
###PasswordResetsコントローラを生成する
ubuntu:~/environment/my_app (password-reset) $ rails generate controller PasswordResets new edit --no-test-framework
Running via Spring preloader in process 10038
create app/controllers/password_resets_controller.rb
route get 'password_resets/new'
get 'password_resets/edit'
invoke erb
create app/views/password_resets
create app/views/password_resets/new.html.erb
create app/views/password_resets/edit.html.erb
invoke helper
create app/helpers/password_resets_helper.rb
invoke assets
invoke scss
create app/assets/stylesheets/password_resets.scss
###config/routes.rb
config/routes.rb
Rails.application.routes.draw do
get 'password_resets/new'
get 'password_resets/edit'
get 'sessions/new'
root 'static_pages#home'
get '/signup', to: 'users#new'
# signupのurlを入力してuser/newのアクションが動き、htmlが表示される。
get '/login', to: 'sessions#new'
# newアクション
post '/login', to: 'sessions#create'
# creteアクション
delete '/logout', to: 'sessions#destroy'
# destroyアクション
resources :users
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
# password_resetsコントローラ にonly以降のアクションを与える
# resourcesを宣言するだけで、コントローラのindex、show、new、edit、create、update、destroyアクションを個別に宣言しなくても1行で宣言が完了
# 特定のコントローラ内アクションにマッピングさせるようルーターに要求しています。
# Railsのリソースフルルーティングでは、各種HTTP verbと、コントローラ内アクションを指すURLが対応付けられます。1つのアクションは、データベース上での特定のCRUD(Create/Read/Update/Delete)操作に対応付けられるルールになっています。
# resources :photosというルーティングがget 'photos/poll'よりも上の行にあれば、resources行のshowアクションがget行の記述よりも優先される
end
###app/views/sessions/new.html.erb
app/views/sessions/new.html
.erb
<% provide(:title, "Log in") %>
<h1>Log in</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(url: login_path, scope: :session, local: true) do |f| %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= link_to "(forgot password)", new_password_reset_path %>
<!--forgetのリンク new_password_reset_pathに移動するようにする-->
<%= f.password_field :password, class: 'form-control' %>
<%= f.label :remember_me, class: "checkbox inline" do %>
<%= f.check_box :remember_me %>
<span>Remember me on this computer</span>
<% end %>
<%= f.submit "Log in", class: "btn btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
###add_reset_to_users.rbを生成する
ubuntu:~/environment/my_app (password-reset) $ rm db/migrate/20220120051051_add_reset_to_users.rb
ubuntu:~/environment/my_app (password-reset) $ rails generate migration add_reset_to_users reset_digest:string \
> reset_sent_at:datetime
Running via Spring preloader in process 17050
invoke active_record
create db/migrate/20220120061244_add_reset_to_users.rb
rails db:migrate
###app/views/password_resets/new.html.erb
app/views/password_resets/new.html
.erb
<!--新しいパスワード再設定画面ビュー-->
<% provide(:title, "パスワードを忘れたら") %>
<h1>Forgot password</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(url: password_resets_path, scope: :password_reset,
local: true) do |f| %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.submit "Submit", class: "btn btn-primary" %>
<% end %>
</div>
</div>
###app/controllers/password_resets_controller.rb
app/controllers/password_resets_controller.rb
class PasswordResetsController < ApplicationController
def new
end
def create
# パスワード再発行の場合
@user = User.find_by(email: params[:password_reset][:email].downcase)
# インスタンス変数にdbからメアドを基に探す
if @user
# 有効性があれば
@user.create_reset_digest
# reset_digestカラムの値を作成
@user.send_password_reset_email
# パスワード再発行用のメールを送信
flash[:info] = "パスワード再発行のためにメールを送信します。"
redirect_to root_url
# ホーム画面に自動で移動する
# view の表示には直接は関係なく、新たな HttpRequest が発行されます。
else
flash.now[:danger] = "Eメールアドレスが見つかりませんでした。"
render 'new'
# 新規登録画面に移動する
end
end
def edit
end
end
###app/models/user.rb
app/models/user.rb
class User < ApplicationRecord
# 継承させる
attr_accessor :remember_token, :activation_token, :reset_token
# 属性remember_token,activation_token,reset_tokenを定義する
# インスタンス変数の読み取り専用のメソッドと書き込み専用のメソッド(セッター/ゲッター)の両方を定義することが出来るメソッド
# 読み取りメソッドとは?
# インスタンス変数の読み取り専用のインスタンスメソッドを「ゲッターメソッド」と呼びます。
# メソッドが呼び出された時に各インスタンス変数を返すように定義します
# ゲッターメソッド(読み取り専用のインスタンスメソッド)を経由することでインスタンス変数(@name)をクラスの外部から参照することが出来ています。
# 書き込みメソッドとは?
# インスタンス変数の書き込み専用のインスタンスメソッドを「セッターメソッド」と呼びます。
# セッターメソッド(書き込み専用のインスタンスメソッド)を経由することでインスタンス変数(@age)をクラスの外部から変更することが出来ます。
# ゲッターメソッドやセッターメソッドなど「インスタンス変数の読み取りや書き込みが出来るメソッド」のことを総じて「アクセサメソッド」と呼ぶ
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]+\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?(attribute, token)
digest = send("#{attribute}_digest")
return false if digest.nil?
BCrypt::Password.new(digest).is_password?(token)
end
# ユーザーのログイン情報を破棄する
def forget
update_attribute(:remember_digest, nil)
end
def activate
# # アカウントを有効にする
update_attribute(:activated, true)
update_attribute(: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))
# 属性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
self.email = email.downcase
end
# 有効化トークンとダイジェストを作成および代入する
def create_activation_digest
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end
end