0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rails チュートリアル 第11章 まとめ

Last updated at Posted at 2019-10-26

メールアドレスを使った認証の方法
8,9章の認証は
----.authenticate?(=====)
とするなら
sessionを使った認証では、----の部分がDBにあるpassword_digestであり、===の部分はUserに入力してもらったpasswordだった
cookiesを使った認証では、---はDBにあるremember_digestであり、===はcookiesに保存されているremember_token

今回の場合、
---の部分は
まず、DBに認証用のdigestを保存するために、開発側で平文を用意し、ハッシュ値をかけてDBに保存する

ユーザーに送ったメールにはactivation_tokenとユーザーのemail情報を含めている
ユーザーがlinkをクリックすると、GETリクエストが送られたとき、userのemail情報がparamsに格納されているので、それを使って、User情報を取得する、そのUser情報からDBのactivation_digestを取得する

そして、===にはactivation_tokenがそのまま入る、ここはsessionやcookiesと変わらない
そのactivation_digestとactivation_tokenを認証する

signup (必要事項の記入) =
before_action (tokenの発行、ハッシュ化してactivation_digestとしてDBに保存) ->
create action (User情報を格納、Userに認証用メールを送信,emailとactivation_tokenが送信) =
User.mailer (account_activationメソッドが呼び出される、controllerに相当) ->
app/views/user_mailer/account_activation.text.erb(メール文面,viewに相当) ->
Userがリンクをクリック = GETリクエストが送られる ->
ルーティングが作動 ->
accout_activation controllerのedit action (実際の認証)

リクエストが送られた時のルーティングとコントローラを準備する必要がある

ルーティング
GET /accout_activations/:id/edit
:id = token
コントローラー
find_byでparams[:emailを取得
authenticated?で認証
params[:id]でtokenを受け取る

attr_accessor activation_token
一時的に保存し、忘れる前にメールで送る
メソッド参照
メソッドをあとで作る
before_create signupの時にだけ反応するコールバック処理
before_save 保存する前に必ず行うコールバック処理
このコールバック処理をメソッド参照で行うことができる

user.rb
#before_createなので、signupする直前に実行
    def create_activation_digest
      self.activation_token  = User.new_token 
#ランダムなトークンを発行し、attr_accessorで作った仮想的な属性に入れておく
      self.activation_digest = User.digest(activation_token)
#そのtokenをハッシュ化させたものをDBのdigestに保存
#正確にはdigestに代入されたあと、createで反映されるのでDBが保存される
    end

メールを送信 - GETリクエストを送る

app/mailers/application_mailer.rb
  def account_activation
    @greeting = "Hi"
    mail to: "to@example.org"  # => return mail object
#中身はapp/views/user_mailer/account_activation.text.erbと
#app/views/user_mailer/account_activation.html.erbとなり
#account_ativationを呼び出した何かがmail objectを実行する ???
  end

textとhtml.erbはviewに似ている
Mailer = Controller
Mailの文面 = View

メールのURLには平文とともにメールアドレスも入れないと誰の平文か分からない

リンクを作る(メールの文面)時に
edit_user_url(user)

http://www.example.com/users/1/editになるらしいが、どこでやった?

その考え方を使い、
http://www.example.com/account_activations/q5lt38hQDc_959PVoo6b7A/edit
としたい

さらに、メールアドレスも含めた文面にしたいので、
account_activations/q5lt38hQDc_959PVoo6b7A/edit?email=foo%40example.com
としたいので、
引数にemailも加えて、最終的に

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

となる

コントローラーの実装
create controller -
User登録をする時に、アカウント認証を行いたいのでcreateアクションに組み込む
今まではsignup(userに必要事項を記入)したら、すぐにloginできる仕様だった

user_controller
def create
    @user = User.new(user_params)
    if @user.save
      log_in @user
      flash[:success] = "Welcome to the Sample App!"
      redirect_to user_path(@user)
    else
      render "new"
    end
end

今回は、これを修正して

user_controller
def create
    @user = User.new(user_params)
    if @user.save
      UserMailer.account_activation(@user).deliver_now
#user_mailer.rbのaccout_activationが呼び出されている
#deliver_nowは返ってきたメールオブジェクトを実際に送信する
      flash[:info] = "Please check your email to activate your account."
      redirect_to root_url
    else

edit actionの実装

accout_activation_controller
@user = User.find_by(email: params[:email]) # メールからUser情報を取得
@user.authenticated?(params[:id]) 
#DBのactivation_digestとメールから取得したactivation_tokenを照合する

しかし、authenticatedメソッドはrememberで固定してしまっているので、DRYの観点からauthenticated?メソッドを抽象化しなければ使えない

元々のauthenticated?メソッドは

def authenticated?(remember_token)
    BCrypt::Password.new(remember_digest).is_password?(remember_token)
end

だったが、以下のように変更

def authenticated?(attribute, token)
  digest = self.send("#{attribute}_digest") 
#sendを使えば動的にメソッドを変更できる、式展開をより実際的に使うことができる
  return false if digest.nil?
  BCrypt::Password.new(digest).is_password?(token)
end

これでeditアクションでauthenticated?を使うことができる

account_activation.cotroller
def edit
    user = User.find_by(email: params[:email])
    if user && !user.activated? && user.authenticated?(:activation, params[:id])
#userはnilチェック
#!user.activated?は何回もクリックされないために、activatedがfalseである時だけ実行
#authenticated?は認証
      user.update_attribute(:activated,    true) #activatedを有効に
      user.update_attribute(:activated_at, Time.zone.now)
      log_in user
      flash[:success] = "Account activated!"
      redirect_to user
    else
      flash[:danger] = "Invalid activation link"
      redirect_to root_url
    end
end
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?