0
3

More than 3 years have passed since last update.

【Rails tutorial・11章】アカウント有効化機能の実装手順を整理してみました【前編・AccountActivationsリソースの作成】

Last updated at Posted at 2020-04-16

はじめに

Railsチュートリアル11章の内容を、少しでも理解の助けとなればと思い、割としっかり目に整理しました!
備忘録です。

前提

Railsチュートリアル1〜10章までの内容が完了していること。

内容

Railsチュートリアル11章のアカウント有効化機能の実装手順を前中後半の3回に分けて整理していきます。
前編である今回は、アカウント有効化機能を実装するのに必要となるリソースや、データモデルを作成していきます!

中編→アカウント有効化メール送信機能の実装
後編→アカウント有効化機能の実装

1.AccountACctivationsリソースを作成する

  ●セッション機能を使って、アカウントの有効化リソースを作成していく。
    ➡︎アカウント有効化リソースを作成するにあたり、Userモデルに必要なデータを追加していくことが必要となる。

    ➡︎注意しなければならない点が1つあって、アカウント有効化リソースはユーザーがアプリから受け取ったメールに貼られたリンクを単にクリックした際に発動する。よってこの場合、ユーザーが送信するリクエストはGETリクエストになるため、updateアクションではなくeditアクションを使う必要がある

1-1.AccountActivationsコントローラの作成

  ●AccountActivationsリソースを作成するために、まずはAccountActivationsコントローラを生成していく。
    ➡︎$ rails g controller AccountActivations

  ●editアクションへアクセスするのに名前付きルートが必要となるため、ルーティングにアカウント有効化に使うリソースを追加する。
    ➡︎resources :account_activations, only: [:edit]
      →︎GETリクエストを受け取り、editアクションへアクセスさせる。
      →URLは「/account_activation//edit」を受け取る。
      →名前付きルートはedit_account_activation_url(token)。
        →_pathではなく、_urlを使うのは、メールからこのURLへアクセスするため。

congig/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'
  get    '/login',   to: 'sessions#new'
  post   '/login',   to: 'sessions#create'
  delete '/logout',  to: 'sessions#destroy'
  resources :users
  #1-1.AccountActivationsリソース追加。
  resources :account_activations, only: [:edit]
end

1-2.AccountActivationのデータモデルを作成していく。

  ●前提として、有効化のメールには一意の有効化トークンが必要である。

  ●有効化トークン作成の方法としては、送信メールとDBの両方に同じ文字列を保存させる方法があるが、DBのデータが漏れた場合の被害が甚大であり危険。
    ➡︎例えば、第三者が新規登録したユーザーアカウントの有効化トークンを盗み、そのユーザーとしてログインしてしまうなどの危険がある。

  ●なので今回もパスワードや記憶トークンの実装で行なったように、仮想の属性とハッシュ化した文字列を使って有効化トークンを作成し、DBに保存されるようにする方法をとることにする。
    ➡︎まずは仮想の有効化トークン属性を追加するために、attr_accessor :actvation_tokenというコードを用意しておく。

    ➡︎次に、DBにactivated属性を追加して、データ型をbooleanとして論理値を取れるようにしたい。
      ➡︎user.activated?と記述した時に、ユーザーが有効化かどうかをテストできるようにするため。

    ➡︎上述した必要なデータモデルをDBへ追加ししたいので、マイグレーションを作成するコマンドを実行する。
      →$ rails g migration add_activation_to_users ¥
      > activation_digest:string activated:boolean activated_at:datetime
        →activation_digest属性、データ型string。
        →activated属性、データ型boolean。
        →activated_at属性、データ型datetime(ユーザーを有効にした時の日時)。

    ➡︎db/migrate/_add_activation_to_users.rbファイルへ移動し、activated属性のデフォルト値をfalseに設定しておく。
      →デフォルトではユーザーを有効化させないため。

    ➡︎コマンドを実行して、マイグレーションの変更をDBに保存。

  ●Activationトークンのコールバックを記述する。
    ➡︎ユーザーが新規登録を完了するには必ずアカウントの有効化が必要になる。

    ➡︎ということは、ユーザーオブジェクトが作成される前にはもう、有効化トークンと有効化ダイジェストが作成されていなければならない。

    ➡︎オブジェクトが"作成される直前"に何らかの処理を実行したい場合、Userモデル内でコールバックを使用しよう。
      →例えばbefore_saveというコールバックを使用すれば、オブジェクトが"保存される直前"、すなわちオブジェクトが作成や更新される瞬間にコールバックが呼び出され、処理を実行してくれる。

    ➡今回は、ユーザーが"作成される直前"なので、before_createコールバックを使用する。
      →コールバックの引数にメソッドを渡すことで、Railsはそのメソッドを呼び出し、ユーザーオブジェクトが作成される前にそのメソッドを実行する。

  ●有効化トークンと有効化ダイジェストを生成するメソッドの定義。(コールバックで使うやつ)
    →メソッド名はcreate_activation_digestとする。
    →ランダムな文字列を生成し、仮想の属性である有効化トークンへ代入する処理を記述する。
    →その有効化トークンをハッシュ化して、有効化ダイジェストへ保存する処理を記述する。
      (→永続セッション作成用に定義したrememberメソッドでは、記憶ダイジェストに値を保存する際update_attributeメソッドを使ったが、今回は何故update_attributeを使わないのかをここで説明する。)
      (→create_activation_digestの場合は、ユーザーが作成される直前に呼び出されるので、更新するダイジェスト属性がそもそも存在しない。要するにユーザーが保存される際、ダイジェストの値も一緒に保存される。)
      (→rememberの場合は、記憶トークンや記憶ダイジェストが、既にDBに存在するユーザーのために作成されるから。)

  ●Userモデルに、上記で示したアカウント有効化用のトークンを生成する処理を行うコードを記述する。
    ➡︎app/models/user.rbファイルヘ移動。

    ➡︎仮想の有効化トークン属性を、attr_accessorへ適用させたコードを記述。
      →attr_accessor :activation_token

    ➡︎有効化トークンと有効化ダイジェストを作成するためのメソッドを記述。
      →Userモデル内でしか使用しないので、外部に公開されないようprivateキーワード内で記述していく。
      →上述した通り、メソッド名はcreate_activation_digestとする。
        →ランダムな文字列を作成するUser.new_tokenメソッドを呼び出し、有効化トークンへ代入する処理を記述。
        →上記の有効化トークンを有効化ダイジェストへ代入する処理を記述。

    ➡︎before_createコールバックに、create_activation_digestメソッドを適用させる記述を行う。

  ●ここで一旦、後々テストする際に必要となるサンプルデータとfixtureに変更を加え、事前にサンプルとユーザーを有効化しておく。
    ➡︎サンプルユーザーを有効化する。
      →db/seeds.rbへ移動。
      →それぞれのユーザーデータにactivated: trueと、activated_at: Time.zone.nowを追加。

    ➡︎fixtureのユーザーを有効化する。
      →test/fixtures/users.ymlへ移動。
      →それぞれのユーザーデータにactivated: trueと、activated_at: <%= Time.zone.now %>を追加。

    ➡︎変更したら、データベースを初期化して、サンプルデータを再度生成し直す。
      →$rails db:migrate:reset
      →$rails db:seed

ターミナル
  #1-2.マイグレーションの作成。
  $ rails g migration add_activation_to_users ¥
    activation_digest:string activated:boolean activated:datetime
db/migrate/[timestamp]_add_activation_to_users.rb
  #1-2.Usersモデルにデータを追加。
  class AddActivationToUsers < ActiveRecord::Migration[5.0]
    def change
      add_column :users, :activation_digest, :string
      add_column :users, :activated, :boolean, default: false
      add_column :users, :activated_at, :datetime
    end
end
ターミナル
  #1-2.マイグレーションの変更をDBに反映させる。
  $ rails db:migrate
app/models/user.rb
class User < ApplicationRecord
  attr_accessor :remember_token, :activation_token
  before_save   :downcase_email #コールバックにメソッドを渡す(追加事項)。
  before_create :create_activation_digest
  .
  .
  .
  private
    #メアドを小文字化するメソッドを定義する(追加事項)。
    def downcase_email
      self.email = email.downcase
    end
 
    #1-2.有効化トークンの作成し、作成した有効化トークンをハッシュ化しダイジェストへ保存。
    def create_activation_digest
      self.activation_token  = User.new_token
      self.activation_digest = User.digest(activation_token)
    end
end
db/seed.rb
  #1-2.サンプルユーザーを有効化しておく。
  User.create!(name:  "Example User",
               .
               .
               .
               activated: true,
               activated_at: Time.zone.now)
 
  99.times do |n|
    .
    .
    .
    User.create!(name:  name,
                .
                .
                .
                activated: true,
                activated_at: Time.zone.now)
  end
test/fixtures/users.yml
  #fixtureのテスト用ユーザーを有効化しておく。
  michael:
    .
    .
    .
    activated: true
    activated_at: <%= Time.zone.now %>
 
  archer:
    .
    .
    .
    activated: true
    activated_at: <%= Time.zone.now %>
 
  lana:
    .
    .
    .
    activated: true
    activated_at: <%= Time.zone.now %>
 
  malory:
    .
    .
    .
    activated: true
    activated_at: <%= Time.zone.now %>
 
  <% 30.times do |n| %>
  user_<%= n %>:
    .
    .
    .
    activated: true
    activated_at: <%= Time.zone.now %>
  <% end %>


最後に

 前編のAccountActivationsリソースの作成はここまでになります。
 中編→アカウント有効化用メール送信機能の実装
 後編のアカウント有効化機能の実装

参考

 Railsチュートリアル 第11章アカウントの有効化

0
3
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
3