Railsチュートリアル第6章　備忘録_前編

##経緯
個人的にこの章から正規表現を初め、難易度がかなり上がった気がする。
バリデーションテェックなど、外したくない部分が多々あったので
確実に理解していくため２回に分けて深掘ろうと思う。

##Userモデル

Railsでは、データモデルとして扱うデフォルトのデータ構造のことをモデル（Model）と呼ぶ。
データベースとやりとりをするデフォルトのRailsライブラリはActive Recordと呼ぶ。
Active Recordのおかげで通常データベースを操作するのに必要なSQLを意識する必要がない。
コントローラ名には複数形(Users)
モデル名には単数形(User)
を用いる。

Userモデルの生成
``$ rails generate model User name:string email:string``

generateコマンドの結果のひとつとして、マイグレーションと呼ばれる新しいファイルが生成される。
マイグレーションは、データベースの構造を切り離し、要求が変更された場合にデータモデルを適合できる。

|users||
|:--|:--|
|id|integer|
|name|string|
|email|string|
|created_at|datetime|
|updated_at|datetime|


マイグレーション実行コマンド
``$ rails db:migrate``
やっぱ元に戻したい
``$ rails db:rollback``

##modelファイル

```app/models/user.rb

class User < ApplicationRecord
end
```
User < ApplicationRecord < ActiveRecord::Base
つまり、ActiveRecord::Baseクラスのすべての機能を持つことになる。

データベースを変更せずにデータモデルを調べるときは、
``$ rails console --sandbox``　を使う。
コンソール終了時に変更をすべてロールバック(取消)してくれる。


###ユーザーオブジェクトをコンソール用に出力

- 引数なし:すべての属性が``nil``で返ってくる。
``>> User.new``

- 引数あり (初期化hash)
``>> user = User.new(name: "Michael Hartl", email: "michael@example.com")``

有効性（Validity） : オブジェクトが有効かどうか
``>> user.valid?``

User.newで作成したUserオブジェクトを保存
``>> user.save``
saveしない限り、created_at,updated_atはnilのまま

Userモデルのインスタンスはドット記法を用いてその属性にアクセス可能。
``>> user.name``
``>> user.email``
``>> user.updated_at``

作成と保存が同時にやりたい
``>> User.create``
削除
``>> User.destroy``

###ユーザーオブジェクトを検索
Active Recordには、オブジェクトを検索するための方法がいくつもある。

過去に作成したユーザーを探す
``>> User.find(ユーザID)``

特定の属性でユーザーを検索する
``>> User.find_by(属性: "属性に対する値")``

最初のユーザ
``>> User.first``

ユーザ全員
``>> User.all``

ユーザの要素数を知りたい（メソッドチェーンを使用）
``>> User.all.length``

###ユーザーオブジェクトを更新

・直接代入してsave
``>> user.name = "Michael Hartl"``
``>> user.save``

・updateメソッド使用
``>>user.update(name: "Michael Hartl", email: "michael@example.com")``


・特定の属性のみを更新したい場合(データの「検証」を回避する効果がある)
``>> user.update_attribute(:name, "Michael Hartl")``

##ユーザーを検証する
要はバリデーションチェックのこと。

- 存在性（presence）の検証
- 長さ（length）の検証
- フォーマット（format）の検証
- 一意性（uniqueness）の検証
- 確認（confirmation） -> よく使われる最終検証

失敗するテストを書き、次にテストを成功させるように実装する。（テスト駆動開発）

###有用性を検証する

```test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com")
  end

  test "should be valid" do
    assert @user.valid?
  end
end
```
setupメソッドを使ってUserオブジェクト（@user）を作成。これは各テストが走る直前に実行される。
@userをsetupメソッド内で宣言。
should be validで、@userの有効性をテストできる。

modelに関係するテストだけ走らせたい場合のコマンド
``$ rails test:models``

Userモデルにはまだバリデーションがないので、このテストは成功する。

###存在性を検証する
最も基本的なバリデーション。

```test/models/user_test.rb
省略
  test "name should be present" do
    @user.name = "     "
    assert_not @user.valid?
  end
省略
```
空白を入れ、nameが存在しない場合はuserが有効でない。

現段階でテストは失敗。

```app/models/user.rb
class User < ApplicationRecord
  validates :name, presence: true
end

  #validates(:name, presence: true)の省略形
```

コンソールにて、valid?メソッドでuser変数が有効かどうかチェック。
``$ rails console --sandbox```
``>> user = User.new(name: "", email: "michael@example.com")``
``>> user.valid?``
``=> false``

失敗したときに作られるerrorsオブジェクトを使ってみる
``>> user.errors.full_messages``
``=> ["Name can't be blank"]``

有効でないuserがデータベースに保存できないことを確認
``>> user.save``
``=> false``

テストも成功する。

###長さを検証する
ユーザー名：50文字以内で制限
メールアドレス：255文字以内で制限

```test/models/user_test.rb
省略
  test "name should not be too long" do
    @user.name = "a" * 51
    assert_not @user.valid?
  end

  test "email should not be too long" do
    @user.email = "a" * 244 + "@example.com"
    assert_not @user.valid?
  end
省略
```
aを掛け算で増やして文字数を稼いでいる。

この時点ではテスト失敗

```app/models/user.rb
class User < ApplicationRecord
  validates :name,  presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 }
end
```
テスト成功する。

###フォーマットを検証する
メールアドレスにおなじみのパターンuser@example.comに合っているかどうか確認する。

%w[]を使うと文字列の配列を簡単に作れる.
これを使って無効なメールアドレスリストを作成していく。

```test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com")
  end
  .
  .
  .
  test "email validation should accept valid addresses" do
    valid_addresses = %w[user@example.com USER@foo.COM A_US-ER@foo.bar.org
                         first.last@foo.jp alice+bob@baz.cn]
    valid_addresses.each do |valid_address|
      @user.email = valid_address
      assert @user.valid?, "#{valid_address.inspect} should be valid"
      #どのメールアドレスでテストが失敗したか特定できるよう、assertメソッドの第二引数でエラーメッセージを追加している。
    end
  end
end
```

user@example,com（ドットではなくカンマになっている）や
user_at_foo.org（アットマーク ‘@’ がない）といった無効なメールアドレスを使って
 「無効性（Invalidity）」についてテスト

```test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com")
  end
  .
  .
  .
  test "email validation should reject invalid addresses" do
    invalid_addresses = %w[user@example,com user_at_foo.org user.name@example.
                           foo@bar_baz.com foo@bar+baz.com]
    invalid_addresses.each do |invalid_address|
      @user.email = invalid_address
      assert_not @user.valid?, "#{invalid_address.inspect} should be invalid"
    end
  end
end
```
テストは失敗。

メールアドレスのフォーマットを検証するためには正規表現を書かなければならない。

```app/models/user.rb
class User < ApplicationRecord
  validates :name,  presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i  #VALID_EMAIL_REGEX：定数
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX }
end
```
残念な点：foo@bar..comのようなドットの連続を誤りとして検出できない.

テストが通る。