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

##はじめに
Railsチュートリアル11章の内容を、少しでも理解の助けとなればと思い、割としっかり目に整理しました！
__備忘録です。__
<br>
##前提
Railsチュートリアル１〜10章までの内容が完了していること。
<br>
##内容
Railsチュートリアル11章の__アカウント有効化機能の実装手順__を前中後半の3回に分けて整理していきます。
前編である今回は、__アカウント有効化機能を実装するのに必要となるリソースや、データモデルを作成__していきます！

中編→[__アカウント有効化メール送信機能の実装__](https://qiita.com/kurawo___D/items/051ce6f6bb0837e3481a)
後編→[__アカウント有効化機能の実装__](https://qiita.com/kurawo___D/items/3f1873530741b4601ef3)
<br>
##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/<token>/edit」を受け取る。
　　　　　　→名前付きルートはedit_account_activation_url(token)。
　　　　　　　　→_pathではなく、_urlを使うのは、メールからこのURLへアクセスするため。

>```ruby: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
			
>```ruby:ターミナル
  #1-2.マイグレーションの作成。
  $ rails g migration add_activation_to_users ¥
    activation_digest:string activated:boolean activated:datetime
```

>```ruby: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
```

>```ruby:ターミナル
  #1-2.マイグレーションの変更をDBに反映させる。
  $ rails db:migrate
```

>```ruby: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
```

>```ruby: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
```

>```ruby: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 %>
```

<br>
##最後に
　前編の__AccountActivationsリソースの作成__はここまでになります。
　中編→[__アカウント有効化用メール送信機能の実装__](https://qiita.com/kurawo___D/items/051ce6f6bb0837e3481a)
　後編の[__アカウント有効化機能の実装__](https://qiita.com/kurawo___D/items/3f1873530741b4601ef3)
<br>
##参考
　[Railsチュートリアル 第11章アカウントの有効化](https://railstutorial.jp/chapters/account_activation?version=5.1#cha-account_activation)