1
0

More than 3 years have passed since last update.

Railsチュートリアル(第6版) 第6章 ユーザーのモデルを作成する

Posted at

第6章

この章はユーザーモデルを作っていく。前章はスタブページまでで終わったが、これからひたすらユーザー登録に関することを学んでいく。
(なんと本章から第12章までひたすら作っていくのでしんどい道となる)
頑張ろう

Userモデル

ユーザー登録するからユーザー登録用ページを作る前に、まずは名前、メールアドレス、パスワード等を保存するためのデータ構造を作成しなければならない。
このデータ構造を、RailsではModel(モデル)という。
また、データベースとやり取りするためのRailsライブラリは、Active Recordと呼ばれる。
通常データベースを使うなら、SQLという言語を使うが、Railsではマイグレーション機能で、データベースの構造を切り離してくれるため、SQLを意識しなくてもOK
(この辺りの機能便利だなーと思った。筆者は仕事でSQLを多少なりと触っていた経験があるので、SQLをいじらず作成できるのはでかい)

なおRailsチュートリアルでは、開発環境ではSQLiteを使用し、本番環境はPostgreSQLを使う。

データベース移行

コンソールでいくつかデータを作成したが、これだけでは永続性が欠けている。ということで、永続性を保つためにモデルを作ることとする。

復習 命名規則
・コントローラー名は、複数形を使う。 例:Users
・モデル名は、単数形を使う。例:User

理由は、コントローラーは様々なデータを持つのに対し、モデルは決まった特定のデータだけを参照するため。

早速、モデルを作成する。

$ rails generate model User name:string email:string

name:stringemail:stringオプションのパラメータを渡し、データベースで使う属性を与えている。

generateコマンドを使うと、マイグレーションファイル、テストファイル、フィクスチャを同時に作ってくれる。

マイグレーションファイルを見てみよう。

/sample_app/db/migrate/20210523082848_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end

タイムスタンプというものが発行されることが分かる。複数の開発者が同じ整数を持つマイグレーションを生成した際に、コンフリクトを起こさないようにするためのもの。

image.png
参照:railsチュートリアル

nameemailだけしか属性を与えていないが、他にもidcreated_atupdated_atが作られている。
先ほどのt.timestampsによってcreated_atupdated_at`というマジックカラムが作成される。作成と更新日時を保持してくれる。

さて、ここまで来たらマイグレーションを適用させよう。

$ rails db:migrate

ついでに、DB Browser for SQLiteというソフトを使えばデータベースの構造を見れる。

演習
スキーマとマイグレーションファイルの比較

/sample_app/db/schema.rb
ActiveRecord::Schema.define(version: 2021_05_23_082848) do

  create_table "users", force: :cascade do |t|
    t.string "name"
    t.string "email"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end
end
/sample_app/db/migrate/20210523082848_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end

2.ロールバック実行

$ rails db:rollback

ロールバックとはもとに戻すことを意味する。

$ rails db:rollback
-- drop_table(:users)
   -> 0.0089s

スキーマの内容を見ると、、、

/sample_app/db/schema.rb
ActiveRecord::Schema.define(version: 0) do

end

drop_tableコマンドを呼び出し、削除している。changeメソッドがcreate_tabledrop_tableのコマンドを知っている。

あとは、もう一度rails db:migrateすればOK

modelファイル

第4章で学んだ継承関係をモデルでもみる事ができる。

例えば、Userモデルは下のような感じだ。

app/models/user.rb
class User < ApplicationRecord
end

class User < ApplicationRecord < ActiveRecord::Baseといった具合に継承している。

演習

2.6.3 :001 > User.new
   (4.5ms)  SELECT sqlite_version(*)
 => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil> 

User.newUserクラスのオブジェクトが生成された。

ユーザーオブジェクト生成

サンドボックスモードでコンソールを起動する。サンドボックスモードはコンソール終了時にすべてロールバックしてくれる。

$ rails console --sandbox

要点だけ
User.newを使うことで、新しいオブジェクトを生成できる。引数なしで読んだ場合は、全ての属性がnilのオブジェクトとなる。

userオブジェクトが有効かどうかを調べるには、user.valid?とすることで調べられる。

・保存するには、saveメソッドを使って、user.saveとして、成功すれば保存する。

・Userモデルのインスタンスの属性にアクセスするには、ドット記法を用いる。
 user.nameuser.email

・モデルの生成と保存を一度に行える方法がある。それは、createメソッドだ。User.create(name: "値", email: "値")とすればOK

createの逆でオブジェクトを削除するには、destroyメソッドを使うが、オブジェクトはメモリ上に残る。

演習
1.user.nameとuser.emailが、どちらもStringクラスのインスタンスであることを確認

>> user.name.class
=> String
>> user.email.class
=> String

2.created_atとupdated_atは、どのクラスのインスタンスか。

>> foo.created_at.class
=> ActiveSupport::TimeWithZone
>> foo.updated_at.class
=> ActiveSupport::TimeWithZone

ユーザーオブジェクトを検索する

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

・1番目のユーザーを探す。User.find(id)

>> User.find(1)

番号を変えれば、その番号に該当するユーザーが取得できる。

・属性と検索値で探す。User.find_by(属性: "値")

>> User.find_by(email: "michael@example.com")

・最初のユーザーを検索する。User.first
 データベースの最初のユーザーを返す。

>> User.first

・デーベースの全てのユーザーを返す。User.all

>> User.all

全てのオブジェクトのクラスがActiveRecord::Relationとなっており、各オブジェクトを配列としてまとめてくれている。
つまりはActiveRecord::Relationクラスで、各オブジェクトを配列という扱いで返してくれるようになっている。

演習

>> User.all.class
=> User::ActiveRecord_Relation
>> User.all.length

ユーザーオブジェクトを更新する。

ユーザーオブジェクトを更新する方法は2通りある。

1つ目
属性を個別に代入する方法

>> user.name = "ZIP"
=> "ZIP"
>> user.save

この方法を必ずsaveを実行する必要がある。saveを行わずreloadすると元のオブジェクトを再読み込みするので、変更が取り消される。

2つ目
updateを使う方法

>> user.update(name: "The Dude", email: "dude@abides.org")

updateメソッドは属性のハッシュを受け取り、成功した時は更新と保存を同時にしてくれる。しかし、検証に一つでも失敗すれば、updateの呼び出しは失敗する。
また、特定の属性のみ更新したい場合は、update_attributeとすることで、検証を回避することができる。

>> user.update_attribute(:name, "El Duderino")

ユーザーを検証する

nameemail属性が与えられたUserモデルを作ってきた。
しかし、現時点ではどんなデータも入力できてしまう。
nameなら、空白とかめっちゃ長い名前とか
emailなら、空白は当然ながら、メールアドレスのフォーマットに従ってないやつとか。
これらを解決しようってのが、検証(Validation)という訳。

検証でよく使われるやつ
・存在性(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を作成する。setupメソッド内に書かれた処理は、各テストが走る直前に実行される。
また、@userはインスタンス変数だが、setupメソッド内で宣言したため、全てのテストでこのインスタンス変数が使えるようになる。
valid?メソッドを使い、Userオブジェクトの有効性をテストできればOK。

$ rails test:models
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

モデルに関係するテストだけ実行している。まだUserモデルにバリデーションがないので、テストは成功している。

存在性を検証する

基本と言っていい「存在性(Presence)」というバリデーション。
これは、渡された属性が存在するかどうかを検証するもの。
存在性のバリデーションがあれば、渡された属性にデータがあるということを保証できる。

name属性の存在性テストを追加

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

  test "name should be present" do
    @user.name = "     "
    assert_not @user.valid?
  end
end

テストする

$ rails test:models
2 runs, 2 assertions, 1 failures, 0 errors, 0 skips

次にバリデーションを追加する。

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

このバリデーション記法は丸カッコと波カッコが省略されている。
省略せずにかくとこんな感じ
validates(:name, {presence: true})
validatesメソッドの第一引数に、ハッシュのキー:nameを渡し、第二引数にオプションハッシュを渡している。メソッドの丸カッコは省略できる&メソッド引数の最後のハッシュは省略できる。

コンソールでやるとこんな感じ

$ rails console --sandbox
>> user = User.new(name: "", email: "michael@example.com")
>> user.valid?
=> false

名前の属性が空白になっているため、存在性の検証でfalseが返ってきている。1つ以上失敗した時、falseを返す。
逆にすべてのバリデーションがOKならtrueを返す。
検証に失敗した時に作られるerrorsオブジェクトを使うと何で失敗したかが分かる。

>> user.errors.full_messages
=> ["Name can't be blank"]

当然保存も失敗する。

>> user.save
=> false

バリデーションを追加したのでテスト

$ rails test:models
2 runs, 2 assertions, 0 failures, 0 errors, 0 skips

同様にメールアドレスのバリデーションも追加
先ずはテストから

test/models/user_test.rb
  test "email should be present" do
    @user.email = "     "
    assert_not @user.valid?
  end

バリデーション追加

app/models/user.rb
validates :email, presence: true

テスト

$ rails test
10 runs, 20 assertions, 0 failures, 0 errors, 0 skips

長さを検証する

次の検証は長さ
あまりにも長い名前やメールアドレスは登録できないようにしたい。
ということで、長さの上限を設ける。

名前は50文字を上限
メールアドレスは、殆どのデータベースの文字列上限の255字としているので、255文字まで

nameemailの長さに対するテスト

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

指定の文字列を作成するには、文字列の掛け算をすればOK

>> "a" * 51
=> "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
>> ("a" * 51).length
=> 51

テスト追加したので、テスト

$ rails test
12 runs, 22 assertions, 2 failures, 0 errors, 0 skips

長さの強制するための検証の引数

app/models/user.rb
class User < ApplicationRecord
  validates :name,  presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 }
end

先ほど追加した存在性の後ろに長さの検証を追加した。
:maximumパラメータと一緒に、:lengthで長さの上限を決められる。

バリデーション追加したのでテスト

$ rails test
12 runs, 22 assertions, 0 failures, 0 errors, 0 skips

フォーマットを検証する

name属性は、空文字でない&51文字未満であればOK
しかし、email属性は、それだけではなく有効なメールアドレスのフォーマットかどうか判定しなければならない。

有効なメールアドレスと無効なメールアドレスのコレクションに対するテストを作る方法がある。
それは、文字列の配列を作れる%w[]というものだ。

>> %w[foo bar baz]
=> ["foo", "bar", "baz"]
>> addresses = %w[USER@foo.COM THE_US-ER@foo.bar.org first.last@foo.jp]
=> ["USER@foo.COM", "THE_US-ER@foo.bar.org", "first.last@foo.jp"]
>> addresses.each do |address|
?>   puts address
>> end
USER@foo.COM
THE_US-ER@foo.bar.org
first.last@foo.jp

まずは、テストを追加
有効なメールフォーマットのテスト

test/models/user_test.rb
  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"
    end
  end

追加したテストのassertメソッドの第2引数にエラーメッセージがある。
これは、どのメールアドレスが失敗したか特定できるようにしたもの。
文字列を調べるのに、inspectメソッドを使用している。
また、eachメソッドを使って各メールアドレスを順にテストしている。

続いて、user@example,comuser_at_foo.org等の無効なメールアドレスを使用し、「無効性(Invalidity)」のテストもする。

test/models/user_test.rb
  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

テスト

$ rails test
14 runs, 28 assertions, 1 failures, 0 errors, 0 skips

メールアドレスのフォーマット検証には次のようなformatというオプションを使う。

validates :email, format: { with: /<regular expression>/ }

このオプションの引数に正規表現を取る。その正規表現の一つが下のもの

VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

モデルに検証を追加した結果が下のもの

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
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX }
end

因みに大文字で始まるものは、Rubyでは定数としている。
現時点では、foo@bar..comの誤りは検出できない。
そのため、下記のように変更すればOK。

VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i

バリデーションを追加したのでテスト

$ rails test:models
7 runs, 15 assertions, 0 failures, 0 errors, 0 skips

一意性を検証する

一意性とは、他とダブらないということ。
同じものがあってはダメ。

一意性のテストの注意点
・メモリ上にオブジェクトを作るだけではなく、レコードをデータベースに登録する必要がある。
ユーザー1を登録して、ユーザー1と同じメールアドレスを持つユーザー2を登録するという状況を作る。

test/models/user_test.rb
  test "email addresses should be unique" do
    duplicate_user = @user.dup
    @user.save
    assert_not duplicate_user.valid?
  end

dupメソッドは同じ属性を持つデータを複製するためのもの。
このままでは、メールアドレスの大文字と小文字が区別されないため、foo@bar.comFOO@BAR.COMFoO@BAr.coMと書いても扱いは同じになる。
なので、テストコードにupcaseを下記に変更

test/models/user_test.rb
  test "email addresses should be unique" do
    duplicate_user = @user.dup
    duplicate_user.email = @user.email.upcase
    @user.save
    assert_not duplicate_user.valid?
  end

メールアドレスの一意性の検証をするために、uniquenessを追加

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
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: true
end

しかし、ここではfalseになるため、:uniqueness:case_sensitveというオプションを使う。

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
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
end

こうすることで、Railsはtrueと判断する。
しかし、まだ問題がある。
それは、Active Recordはデータベースのレベルまで一意性を保証してない。
現状の検証では、ユーザー登録する前に検証している。なので、トラフィックが多い時や素早く連続2回クリックするとリクエストが2つ連続で送信される。
そうすると、最初のリクエスト1は検証にパスするユーザーを作成し、リクエスト2も同様になる。結果的に、リクエスト1とリクエスト2が保存される。
解決策は、emailカラムにインデックスを追加し一意性が担保されればOK。

もしインデックスがないと?

インデックスがないと、渡されたemailアドレスと、データベースレコードを一人ずつ比較していかなければならない。このことを全表スキャンといって、ユーザーが多ければ多いほどよろしくない。

インデックスを追加すれば、図書館の索引と同じように目印を辿るので簡単に見つけられる。

今回既にマイグレーションが生成されているものに対して、モデル構造に新たにインデックスを追加するので、migrationジェネレータを使い直接作成する。

$ rails generate migration add_index_to_users_email

一意性のマイグレーションが未定義なので、下記のように設定

db/migrate/[timestamp]_add_index_to_users_email.rb
class AddIndexToUsersEmail < ActiveRecord::Migration[6.0]
  def change
    add_index :users, :email, unique: true
  end
end

usersテーブルのemailカラムにadd_indexを使って追加した。
また、unique: trueで一意性を確保

マイグレートする

$ rails db:migrate

テストがREDになるためtest/fixtures/users.ymlの中身を消しておく。

Foo@ExAMPle.Comfoo@example.comを同列の文字列と解釈させるため、データベースに保存する前に文字列をすべて小文字に変換する。
これを実現するために、コールバック(callback)メソッドを利用する。

保存する前に実行したいので、before_saveというコールバックを使う。

app/models/user.rb
class User < ApplicationRecord
  before_save { self.email = email.downcase }
  validates :name,  presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: true
end

downcaseという文字列メソッドで小文字に変換している。
また、uniqueness:{case_sensitive: false}uniqueness: trueに戻してOK。理由は、全部小文字にするから。

テストも大文字変換していた箇所を削除した。

なおself.email = self.email.downcaseともかけるが、右辺のselfは省略できるため、self.email = email.downcaseと書いてもOK。
また、破壊的メソッドを使ったこれもOK
before_save { email.downcase! }

""セキュアなパスワードを追加する
パスワードの値をそのままデータベースに保存するのではなく、ハッシュ化して保存する。
ハッシュ関数を使って、不可逆的なデータをする処理の事を指す。

ユーザー認証は
①パスワード送信
 ↓
②ハッシュ化
 ↓
③データベース内のハッシュ化された値と比較
という手順で行う。

生のパスワードは危険なので、、、

ハッシュ化されたパスワード

Userモデルで、has_secure_passwordメソッドを呼び出せばほぼ完了

has_secure_passwordの機能
 ・password_digestという属性が保存できる
 ・passwordpassword_confirmationが使える。また、存在性と値が一致するかのバリデーションも追加される。
 ・authenticateメソッドが使える。

まだモデル内にpassword_digestという属性がない。従ってUserモデルにpassword_digestのマイグレーション追加のコマンドを実行

$ rails generate migration add_password_digest_to_users password_digest:string

usersとすればusersテーブルに変更を与えることを伝えられ、password_digest:stringという引数を与えることで、完全なマイグレーションを生成するための情報をRailsに与えられる。

マイグレーション実行

$ rails db:migrate

has_secure_passwordを使ってパスワードをハッシュ化するために、最先端のハッシュ関数であるbcryptが必要になる。
Gemfileに
gem 'bcrypt', '3.1.13'
と打ち込んで、bundle install実行

Userモデルにpassword_digest属性を追加、bcryptも追加したので準備OK
Userモデル内に
has_secure_password
と書く。

ここでテストすると失敗する。
理由は、has_secure_passwordには、仮想的なpassword属性とpassword_confirmation属性に対するバリデーション機能も追加されているから。
テストのsetup内にpassword: "foobar", password_confirmation: "foobar"を追加する。

test/models/user_test.rb
  def setup
    @user = User.new(name: "Example User", email: "user@example.com",
                     password: "foobar", password_confirmation: "foobar")
  end

これでテストは成功する。

演習

> user = User.new(name: "zippp", email: "zippp@foo.com") 
   (0.4ms)  SELECT sqlite_version(*)
 => #<User id: nil, name: "zippp", email: "zippp@foo.com", created_at: nil, updated_at: nil, password_digest: nil> 
> user.valid?
  User Exists? (0.8ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "zippp@foo.com"], ["LIMIT", 1]]
 => false 
> user.errors.full_messages
 => ["Password can't be blank"] 

パスワードの最小文字数

パスワードの長さが6文字以上の検証をするテストを追加

test/models/user_test.rb
  test "password should be present (nonblank)" do
    @user.password = @user.password_confirmation = " " * 6
    assert_not @user.valid?
  end

  test "password should have a minimum length" do
    @user.password = @user.password_confirmation = "a" * 5
    assert_not @user.valid?
  end

ここでは多重代入を使っている。

@user.password = @user.password_confirmation = "a" * 5

パスワードとパスワード確認に対して同時に代入している。

次に、バリデーション追加。maximumの反対のminimumというオプションを使えばOK

validates :password, presence: true, length: { minimum: 6 }

因みに、ここのコードにも存在性のバリデーションを入れないと、既にあるユーザーのパスワードを空白6文字で更新できる問題が発生するため存在性のバリデーションがある。

テストは成功した。

演習

> user = User.new(name: "zipp", email: "zipp@example.com", password: "foo")
   (0.4ms)  SELECT sqlite_version(*)
 => #<User id: nil, name: "zipp", email: "zipp@example.com", created_at: nil, updated_at: nil, password_digest: [FILTERED]> 
> user.valid?
  User Exists? (0.2ms)  SELECT 1 AS one FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "zipp@example.com"], ["LIMIT", 1]]
 => false 
> user.errors.full_messages
 => ["Password is too short (minimum is 6 characters)"] 

ユーザーの作成と認証

railsコンソールを使って、開発環境にユーザーを一人新規作成する。

$ rails console
>> User.create(name: "Michael Hartl", email: "michael@example.com",
?>             password: "foobar", password_confirmation: "foobar")

password_digest属性を参照すると、、、

 => #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-05-24 21:42:11", updated_at: "2021-05-24 21:42:11", password_digest: [FILTERED]> 
2.6.3 :007 > user.password_digest
 => "$2a$12$0rJcCo8udpl672xQqpPw9.hAxiuTQPc01N2bWLl5utKJMCkN4T2Oq" 

見事にパスワードがハッシュ化されている。
前回has_secure_passwordをUserモデルに追加したので、そのオブジェクト内でauthenticateメソッドが使えるようになった。
このメソッドは、引数の文字列をハッシュ化した値と、データベース内のpassword_digestカラムの値を比較する。

間違ったパスワードだと、、、false

>> user.authenticate("foobaz")
false

正しいパスワードだとOK

> user.authenticate("foobar")
 => #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-05-24 21:42:11", updated_at: "2021-05-24 21:42:11", password_digest: [FILTERED]> 

正しいパスワードを入れると、ユーザー情報を返す。
!!を付けて!!user.authenticate("foobar")とすれば、理論値で返してくれる。

最後に

あとは、GithubとHerokuにあげればOK

ユーザーモデル、検証、パスワード等追加して何となくWEBアプリケーションらしくなってきた。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0