mako4kamiya / tctr50_Baukis2_Rails6

【Ruby on Rails 6 実践ガイド】Dockerを使って顧客管理システムを作る。
MIT License
0 stars 0 forks source link

Chapter 7 ユーザー認証(1) #12

Closed mako4kamiya closed 4 years ago

mako4kamiya commented 4 years ago

ユーザー認証を実装するための、データベース、モデルを作成する。sessionについても学ぶ。

mako4kamiya commented 4 years ago

docker-compose downしちゃったから、bundle installもう一回やらないといけなかた。 docker-compose stopで止める。docker-compose restartで再起動。

mako4kamiya commented 4 years ago

bin/rails g model StaffMember

mako4kamiya commented 4 years ago
class CreateStaffMembers < ActiveRecord::Migration[6.0]
  def change
    create_table :staff_members do |t|

      t.timestamps
    end
  end
end

ブロック変数tTableDefinitionオブジェクト。 このオブジェクトの書くメソッドを呼び出すことでテーブルの定義を行う。 Active Record マイグレーション

t.timestampscreated_atupdated_atカラムを生成するメソッド。

TableDefinitionオブジェクトのcolumnメソッド

一般的には t.column :email, :stringだけど、省略して下記のように書く。 t.string :email

mako4kamiya commented 4 years ago
class CreateStaffMembers < ActiveRecord::Migration[6.0]
  def change
    create_table :staff_members do |t| #tはTableDefinitionオブジェクト
      t.string :email, null: false                      # メールアドレス
      t.string :family_name, null: false                # 姓
      t.string :given_name, null: false                 # 名
      t.string :family_name_kana, null: false           # 姓(カナ)
      t.string :given_name_kana, null: false            # 名(カナ)
      t.string :hashed_password                         # パスワード
      t.date :start_date, null: false                   # 開始日
      t.date :end_date                                  # 終了日
      t.boolean :suspended, null: false, default: false # 無効フラグ

      t.timestamps
    end

    add_index :staff_members, "LOWER(email)", unique: true #PostgreSQLは大文字と小文字を区別してしまう。
    add_index :staff_members, [ :family_name_kana, :given_name_kana ] #複合インデックス
  end
end

インデックスをつけることで、検索が高速化する。 複合インデックスとは?

mako4kamiya commented 4 years ago

余談。 bin/rails db:setupコマンドは、 bin/rails db:create,bin/rails db:schema:load,bin/rails db:seed を一気に実行する。 開発したアプリケーションを誰かに渡したときに、その人がデータベースを初期化して立ち上げるときには、bin/rails db:setupをつかう。 createもしてくれるし、migrateして作られたschemaもロードするし。

mako4kamiya commented 4 years ago

Active Record はRubyの世界とデータベースの世界を結びつける。

mako4kamiya commented 4 years ago

rails runner

作ったテーブルにどんなカラムがを持っているかを調べる。 `$ bin/rails r "StaffMember.columns.each { |c| p [ c.name, c.type ] }" image

### rails c と何が違うの?

rails c

consoleコマンドを使うと、コマンドラインでRailsアプリケーションとやり取りすることができます。rails consoleは内部的にIRBを使っているので、IRBを使ったことがあれば簡単に扱えます。IRBは、思いついたアイデアを試してみたり、ウェブサイトにアクセスすることなくサーバのデータを変更したりするのに役立ちます。

**rails r***

runnerコマンドを使うと、非対話的にRailsの文脈でRubyのコードを実行することができます。たとえば次のようになります。 $ rails runner "Model.long_running_method"

使い分けがよくわからない。

mako4kamiya commented 4 years ago

idの主キー(primary key)を任意の名前ものに変更する。

idの主キー(primary key)は、自動的にセットされる。 何らかの理由でidの表記を変えたいときは、create_tableメソッドのprimary_keyオプションで変えられる。 create_table :staff_members, primary_key: "member_id" do |t|

mako4kamiya commented 4 years ago

モデルとデータベースの名前は変えられる。

Railsはモデル名に対してそれにsをつけたテーブル名を作成する。 例)StaffMemberモデル、staff_membersテーブル

以下をモデルの上に書くと変えられる。 self.table_name = "M_SHOKUIN"

Railsを用いずに開発されたシステムをRailsで移植する場合に使う。

mako4kamiya commented 4 years ago

パスワードのハッシュ化

Gem bcryptを使って、パスワードをハッシュ化し、平文で保存しない。

以下をapp/models/staff_member.rbに追加

class StaffMember < ApplicationRecord
    def password=(raw_password)
        if raw_password.kind_of?(String)
            self.hashed_password = BCrypt::Password.create(raw_password)
        elsif raw_password.nil?
            self.hashed_password = nil
        end
    end
end

password=メソッドに文字列の引数が渡されたとき、その引数をraw_passwordに入れて、BCrypt::Password.createメソッドを実行してハッシュ化する。ハッシュ化した値をStaffMembersモデルhashed_password属性にセットする。 引数が空ならnilを入れる。

Rspecでテスト

spec/models/staff_member_spec.rbに追加

RSpec.describe StaffMember, type: :model do
  describe "#password=" do
    example "文字列を与えると、hashed_passwordは長さ60の文字列になる" do
      member = StaffMember.new
      member.password = "baukis"
      expect(member.hashed_password).to be_kind_of(String)
      expect(member.hashed_password.size).to eq(60)
    end
  end
end

おさらいRspecの書き方 expect(ターゲット).to マッチャー

be_kind_ofは、member.hashed_passwordあるクラスのインスタンスであるかどうかを調べている。 BCrypt::Password.createメソッドの戻り値は、BCrypt::Passwordクラスのインスタンスだが、BCrypt::PasswordはStringスラスを継承しているため、be_kind_of(String)で調べてる。

もう1つ追加。

    example "nilを与えると、hashed_passwordはnilになる" do
      member = StaffMember.new(hashed_password: "x")
      member.password = nil
      expect(member.hashed_password).to be_nil
    end

hashed_password属性にnilではない何か(x)がセットされているオブジェクトに対して、引数にnilを入れたpassword=メソッドを呼び出すと、 hashed_passwordがnilになるのを確かめる。 image

mako4kamiya commented 4 years ago

seedデータの作成

db/seeds.rb

table_names = %w(staff_members administrators staff_events customers)

table_names.each do |table_name|
    path = Rails.root.join("db", "seeds", Rails.env, "#{table_name}.rb")
    if File.exist?(path)
        puts "Creating #{table_name}...."
        require(path)
    end
end

db/seeds/development/staff_members.rb

StaffMember.create!(
    email: "taro@example.com",
    family_name: "山田",
    given_name: "太郎",
    family_name_kana: "ヤマダ",
    given_name_kana: "タロウ",
    password: "password",
    start_date: Date.today
)

bin/rails db:seedで実行すると、「Creating staff_members....」と表示される。

mako4kamiya commented 4 years ago

get "login" => "sessions#new", as: :login asは、ルーティングに名前をつける。erbでシンボルでURLパス参照できる。