スポンサーリンク
Railsチュートリアル6章を走破しました。
#Railsチュートリアル の第6章を走破しました! https://t.co/qluZpzQdFu @RailsTutorialJP#プログラミング学習 #駆け出しエンジニアと繋がりたい
— じゅに💻脱サラに命かける人 (@Jyu210) December 9, 2019
スポンサーリンク
Railsチュートリアル6章の内容
- ユーザーのデータモデルの作成
- データを保存する手段の確保
6.1 Userモデル
6.1.1 データベースの移行
- Railsはデータを保存する時にデフォルトでRDB(リレーショナルデータベース)を使用する
- モデルを作成する構文は以下のとおり
1$ rails generate model モデル名 カラム名1:データ型 カラム名2:データ型, ・・・ - コントローラを作成する場合には「複数形」、モデルを作成する場合は「単数形」を指定する
- 上記コマンドを実行した結果、マイグレーションファイルというデータベース更新情報が記述されたファイル(db/migrate/日付_create_テーブル名.rb)と、モデルのコードファイル(app/models/モデル名.rb)が作成される
- マイグレーションファイルはデータベースへの変更を定義した「changeメソッド」の集まり
- モデル名は「単数形」だがテーブル名は「複数形」となる
(モデルはひとつのを表すが、テーブルはモデルの集合体であるため) - モデルを作成する時に「id」という各レコード(行)を一意にするカラム(列)が自動的に作成される
- モデルを作成する時に「created_at」「udpated_at」というカラム(列)が自動的に作成される(「changeメソッド」の「t.timestamp」の記述によって)
- マイグレーションファイルの内容をデータベースに反映時には以下のコマンドを実行する
1$ rails db:migrate - マイグレーションした内容を元に戻したい場合は以下のコマンドを実行する
1$ rails db:rollback
6.1.2 modelファイル
- 特になし
6.1.3 ユーザーオブジェクトを作成する
- Railsコンソールでの更新結果をデータベースに反映したくない場合はRailsコンソールをサンドボックスモードで起動すると、Railsコンソール終了時に全てロールバックされる
1$ rails console --sandbox - モデルから作成したオブジェクトが有効であるか確認するには「valid?メソッド」を使う
- オブジェクトの内容をデータベースに保存する時は「saveメソッド」を使う。
保存が成功した場合はtrue、失敗した場合はfalseが返る。 - 「saveメソッド」実行時に「id」「crated_at」「updated_at」の値が生成され、オブジェクトともデータベースにも反映される
- 「crateメソッド」を使用すると「newメソッド」と「saveメソッド:を同時に行い、対象のオブジェクト自体を返す
- 「destroyメソッド」は「crateメソッド」と逆の機能で、対象のオブジェクトを返す(メモリ上に残っている)
6.1.4 ユーザーオブジェクトを検索する
- 「モデル名.find(id)」で指定したidのデータを検索し、見つかった該当のオブジェクトを返し、見つからなかったら例外(ActiveRecord::RecordNotFound)が発生する
- 特定のカラムの値でデータを検索する場合は、「モデル名.find_by(カラム名: カラム値)」で検索できる
- 「モデル名.first」でデータベースの先頭を返す
- 「モデル名.all・で全てのデータを返す
6.1.5 ユーザーオブジェクトを更新する
- 生成したオブジェクトの「オブジェクト.カラム名 」に値を代入後に、「saveメソッド」を実行することでデータの更新が行える
- 「saveメソッド」を実行する前に「reloadメソッド」を実行するとデータベースの情報を元にオブジェクトが再読み込みされ、更新前の値に戻る
- 「update_attributesメソッド」を使用することで、データの更新と保存まで一度に行うことができる。
1オブジェクト.update_attributes(カラム名1: カラム値, カラム名2: カラム値, ・・・) - 「update_attributesメソッド」ではどれか1つのカラムでも検証に失敗すると、全てのカラムのデータ更新が失敗となる
- 特定のカラムのみを更新したい場合は「「update_attributeメソッド」を使う。このメソッドはデータの検証は行われない
1オブジェクト.update_attribute(カラム名: カラム値)
6.2 ユーザーを検証する
6.2.1 有効性を検証する
- モデルのバリデーション(検証)機能はテスト駆動開発と相性が良い(まず失敗するテストを書き、次にテストを成功させるように実装する)
- テストは有効なモデルのオブジェクトを作成し、その属性のうちの1つを有効でない属性を意図的に変更するように行う
- 作成時の状態に対しても書いておくと、オブジェクトとバリデーションのどちらに問題があったかを切り分けしやすい
- テストコードの例は以下のとおり(Userモデル)
123456789101112131415require 'test_helper'class UserTest < ActiveSupport::TestCase# setupメソッドの中で作成したインスタンス変数は全てのテストで使用可能となるdef setup@user = User.new(name: "Example User", email: "user@example.com")end# 作成したオブジェクトが有効かチェックするテストtest "should be valid" do# valid?がtrue=テスト成功、false=テスト失敗assert @user.valid?endend - モデルのテストのみを実行する場合は以下のコマンドを実行する
1$ rails test:models
6.2.2 存在性を検証する
- まず以下のようなテストを準備する
1234test "テスト名" do@インスタンス変数.カラム名 = " "assert_not @インスタンス変数.valid?end - モデルの検証は「validatesメソッド」を使用する
- 各カラムの存在を確認する場合は「validates :カラム名, presence: true」と記述する
- 検証でエラーが発生した場合は「オブジェクト.errors.full_messages」で何でエラーとなったかのヒントが得られる
6.2.3 長さを検証する
- まずは以下のようなテストを準備する
1234test "テスト名" do@インスタンス変数.カラム名 = "a" * 制限文字数assert_not @インスタンス変数.valid?end - 各カラムの最大長さを検証する場合は「validates :カラム名, length: { maximum: 制限文字数 }」とする
6.2.4 フォーマットを検証する
- まずは以下のようなテストを準備する
12345678test "テスト名" dovalid_addresses = %w[XXX@XXX,com XXXX_XXXX_XXX メールアドレス3メールアドレス4 メールアドレス5]valid_addresses.each do |valid_address|@インスタンス変数.カラム = valid_address# 第二引数にエラ〜メッセージを追加し、どのメールアドレスで失敗したか特定できるようにしているassert @インスタンス変数.valid?, "#{valid_address.inspect} should be valid"end - メールアドレスの検証は「formatオプション」を使う
12345# <regular expression>部分は正規表現validates :email, format: { with: /<regular expression>/ }# Railsチュートリアルおすすめの正規表現VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
6.2.5 一意性を検証する
- メールアドレスは大文字、小文字を区別しないため、実際に一意性を検証しようとすると、大文字、小文字を区別しないような実装が必要
- まずは以下のようなテストを準備する
12345678test "テスト名" do# dupは同じ属性を持つデータを複製するメソッド変数 = @インスタンス変数.dup# メールアドレスを全て大文字に変換して大文字、小文字を区別しないようにする変数.email = @user.email.upcase@インスタンス変数.saveassert_not 変数.valid?end - 一意性を検証するには「:uniquenessオプション」を使う
1validates :カラム名: uniqueness: ture - 大文字、小文字を意識しないようにするには、さらに「:case_sensitiveオプション」を追加する(case_sensitiveがfalseのときuniquenessはtrueと判断される)
1validates :カラム名: uniqueness: { case_sensitive: false } - 上記のチェックを行ったとしても同時に複数のリクエストがあった場合に、バリデーションでは防げない場合があるので、データベースにインデックスを追加する必要がある
- 後からデータベースの変更を行う場合は、まず以下のコマンドでマイグレーションファイルを作成する
1$ rails generate migration ファイル名 - 作成されたマイグレーションファイルに以下を定義して「rails db:migrate」する
12345class ファイル名 < ActiveRecord::Migration[5.0]def changeadd_index :テーブル名, :カラム名, unique: trueendend - データベースによっては大文字、小文字を区別しないものが存在するので、それに対応する必要もあり、モデルのバリデーションに以下を追加する必要がある
12# データを保存する前にメールアドレスを全て小文字にするbefore_save { self.email = email.downcase }
6.3 セキュアなパスワードを追加する
6.3.1 ハッシュ化されたパスワード
- セキュアなパスワードの実装は「has_secure_passwordメソッド」を呼び出すことでほとんど完了する
- 「has_secure_passwordメソッド」はUserを管理するモデルで以下のように記述するとで
123456class User < ApplicationRecord...has_secure_passwordend
has_secure_passwordメソッドを実装することで使える機能
- ハッシュ化したパスワードをデータベースの「password_digest」という属性に保存できるようになる
- 2つのペアの仮想的な属性(「password」と「password_confirmation)が使えるようになる
- 存在値と値が一致するかどうかのバリデーションが追加される
- 「authenticateメソッド」が使えるようになる
(引数の文字列がパスワードと一致すると、Userを管理するオブジェクトを、一致しないとfalseを返す)
has_secure_passwordメソッドを使用するための条件
- 「has_secure_passwordメソッド」を使用するにはデータベース「password_digest」というカラムが必要
- ハッシュ関数「bcrypt」を使用するために「bcrypt」のgemのインストールが必要
6.3.2 ユーザーがセキュアなパスワードを持っている
- 特になし
6.3.3 パスワードの最小文字数
- 「変数 = 変数 = 値」ということで2つの変数に同時に同じ値を代入できる(多重代入)
6.3.4 ユーザーの作成と認証
- 特になし
感想
内容としてはProgateで学習したユーザー認証+αの内容でしたが、メールアドレスの有効性を確認する大変さというか面倒くささが身にしみました。
でも、Webアプリにとってユーザー管理、認証をおろそかにすると、個人情報の流出などといった大変な事態に発展するのできちんとおさえて置く必要がありますね。
次の章では実際のユーザー登録フォームの作成に入るので、しっかりと身につけていきます。
スポンサーリンク