全体像の把握
Modelを作成。Application recordを継承したクラスでは、情報を永続的に保存できる。
User.create User.find_by User.saveなどの操作。
ValidationをTDDで実装
フォームで実現したいこと
永続的なデータを保存したい、一時的な変数ではなく
そのためにはDBを使う必要がある
DBを扱うには別の言語を学ぶ必要があるが、RailsのActiveRecordを使えば、変数のように保存できる
ユーザー用のデータモデルを作成(以下2つのファイルが自動生成)
rails g model User name:string email:string
DBの変更を反映
rails db:migrate
をすると、db/にdevelopment.sqlite3というバイナリファイルが作成される
ここにDBが保存される
migrationファイルの中身を確認(自動生成1)
class CreateUsers < ActiveRecord::Migration[5.1] #クラスの継承
def change #changeメソッドの定義
create_table :users do |t| #create_tableというブロック付きメソッドの定義
t.string :name #t.stringのnameというシンボル
t.string :email
t.timestamps
end
end
end
モデル(自動生成2)
app/model/user.rb
usersのtableが見つからないというエラーが出た時は、もう一度rails db:migrate
app/model/user.rbで、ApplicationRecordを継承していることで、Userクラスに何ができるようになったのかがポイント
・Rail console上で、User.newを使いnameとemailを作成する。普通なら、consoleを閉じると、データは消えるはずだが、u(変数名).saveとするとDBに保存されるため、次にconsoleを立ち上げても、Userのデータが残っている
・継承していることで、DBに保存したり(save)、DBから情報を取得したり(all)、情報を検索したり(find_by)、情報を更新する(update_attributes)ことができる
・普通更新する時はu[:name] = "---"だが、u.name = "^^^"のように代入することもできる
・User.createは作成と保存を同時に行える。戻り値を生成しているので、変数に入れることもできる
foo = User.create(---)
・Validationができるようになる
Validation
テスト(test/models/user_test.rb)と修正(app/models/user.rb)を繰り返すTDD
# setupはtest do-endの直前で呼ばれる
def setup
@user = User.new(
name: "Example User",
email: "user@example.com")
end
# サンプルデータの形式が適切であるかのチェック
# valid?はvalidationが全て通るべきという意味
test "should be valid" do
assert @user.valid?
end
# nameが空文字のユーザーはvalidationではじけているべき(assert_not)であるというチェック
test "name should be present" do
@user.name = " "
assert_not @user.valid?
end
test "email should be present" do
@user.email = " "
assert_not @user.valid?
end
# nameが51字以上の場合にはvaliではじけているべき
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
#成功しているemailのフォーマットは全て通るべき
test "email validation should accept valid addresses" do
#成功しているemailのフォーマットを配列で作成
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 #変数に代入
# validationを通っているかチェック、さらに失敗したならどのemailで失敗したのか表示
assert @user.valid?, "#{valid_address.inspect} should be valid"
end
# 失敗しているemailのformatは全てはじけているべきである
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
#一意性の確認
test "email addresses should be unique" do
#@user.dupで@userを複製する
duplicate_user = @user.dup
@user.save #@userを保存
#@userが保存されているので、同じデータのduplicate_userは保存されずにはじかれるべき
assert_not duplicate_user.valid?
end
一意性の検証
railsだけではなくDBでも検証する仕組みを作る(ほぼ同時のユーザー登録に対処)
すでにあるモデルにカラムを追加したい
rails g migrationの形式は、ここが初めて
rails generate migration add_index_to_users_email
DBにemailカラムが一意であることを確認させる
def change
add_index :users, :email, unique: true
# add_index :テーブル名, :カラム名, 一意性の確保
end
indexであることに注意
Password
passwordはハッシュ関数をかけて、ハッシュ値に変換してからDBに保存
DBにハッシュ値を保存するための場所を準備
rails generate migration add_password_digest_to_users password_digest:string
# usersテーブルにpassword_digestカラムを追加したい
# この形式で書くと自動生成してくれる
# 先のadd_indexと違い add_columnだから、追加したいカラムとデータ型password_digest:string
rails db:migrate
ハッシュ関数の用意
1.gem 'bcrypt', '3.1.12' #gemインストール
2.has_secure_password を追加
has_secure_passwordはpasswordとpassword_confirmationを最初から用意してくれている
password,confのカラムはないが、アクセスすることはできる(u.password)
代入できるが、セーブはしない、ハッシュ値をかけたダイジェストだけが保存されている
Passwordのテスト
# 空文字で6字にしたらはじかれているべき
# valiではpresenceで対処
test "password should be present (nonblank)" do
@user.password = @user.password_confirmation = " " * 6
assert_not @user.valid?
end
# 文字数が5のpasswordははじかれているべき
test "password should have a minimum length" do
@user.password = @user.password_confirmation = "a" * 5
assert_not @user.valid?
end
認証の方法
u.authenticate("---")を使うと、引数の値と本当のパスワードが正しいかチェックし、一致したらユーザーオブジェクトを返し、一致しなかったらfalseを返してくれる
未確認
herokuにデプロイした後、dbを使ったので、heroku run