経緯
個人的にこの章から正規表現を初め、難易度がかなり上がった気がする。
バリデーションテェックなど、外したくない部分が多々あったので
確実に理解していくため2回に分けて深掘ろうと思う。
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 |
| string | |
| created_at | datetime |
| updated_at | datetime |
マイグレーション実行コマンド
$ rails db:migrate
やっぱ元に戻したい
$ rails db:rollback
modelファイル
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) -> よく使われる最終検証
失敗するテストを書き、次にテストを成功させるように実装する。(テスト駆動開発)
有用性を検証する
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 "name should be present" do
@user.name = " "
assert_not @user.valid?
end
省略
空白を入れ、nameが存在しない場合はuserが有効でない。
現段階でテストは失敗。
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 "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を掛け算で増やして文字数を稼いでいる。
この時点ではテスト失敗
class User < ApplicationRecord
validates :name, presence: true, length: { maximum: 50 }
validates :email, presence: true, length: { maximum: 255 }
end
テスト成功する。
フォーマットを検証する
メールアドレスにおなじみのパターンuser@example.comに合っているかどうか確認する。
%w[]を使うと文字列の配列を簡単に作れる.
これを使って無効なメールアドレスリストを作成していく。
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)」についてテスト
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
テストは失敗。
メールアドレスのフォーマットを検証するためには正規表現を書かなければならない。
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のようなドットの連続を誤りとして検出できない.
テストが通る。