1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

基礎Ruby on Rails Chapter8 単数リソース

Last updated at Posted at 2018-09-27

基礎Ruby on Rails Chapter7 バリデーションと国際化
基礎Ruby on Rails Chapter8 アクション・コールバック/マイアカウントページの作成

単数リソース

単数リソースとは

  • member等と比較して、単数リソースとは1つしか存在しないもの。
  • 例えば「セッション」「自分のアカウント」「自分のパスワード」など、自分自身の情報。

単数リソースのルーティング

  • ルーティングを設定するには、routes.rbの中で、resourcesメソッドではなく、単数形のresourceを使う。
resource :account
  • 集合である、indexアクションはない。
  • idパラメータもない。
  • membersテーブルの自分自身のレコードのみを使う。

|アクション|パス|HTTPメソッド|パスを示すシンボル|パスを返すメソッド|
|:--|:--|:--|:--|:--|:--|
|show|/account|GET|:account|account_path|
|new|/account/new|GET|:new_account|new_account_path|
|edit|/account/edit|GET|:edit_account|edit_account_path|
|create|/account|POST|:account|account_path|
|update|/account|PATCH|:account|account_path|
|destroy|/account|DELETE|:account|account_path|

セッションを使ったログイン機能

セッションとは

Railsのセッション

  • Railsはセッションデータを複合化してクッキーに保存するが、暗号化はしないので、ユーザーがデータを解読できる。
  • ただし、改ざんした場合はエラーになる。

セッションデータへのアクセス

  • 「session[:データ名]=値」でセッションに値を入れる。
  • 「session[:データ名]」でセッションから値を取り出す。
  • 「session.delete(:データ名)」でセッションのデータを消す。
  • 「cookie[:データ名]=値」でクッキーに値を入れる。
  • 「cookie[:データ名]」でクッキーから値を取り出す。
  • cookieの有効期間の設定
cookies[:name] = { value: "sato", expires: 30.days.from_now }
  • セッションデータの保存期間
  • 自動ログインには、cookieの代わりにcookie.signedを使う。
cookies.signed[:member_id] = member.id

パスワードの保存

ハッシュ値とbcrypt

  • パスワードをそのまま保存するのではなく、ハッシュ値を保存する。通常Ruby on Railsでは、bcryptを使う。
  • Gemパッケージ、bcrypt-rubyを組み込む必要がある。以下のようにコメントを外す。
Gemfile(一部)
# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'
  • bundle installを実行する。
$ bundle install

ハッシュ値を保存するカラムの追加

  • パスワードのハッシュ値を保存するカラムを追加する。
  • マイグレーションスクリプトを作成する。
$ bin/rails g migration AlterMembers1
  • マイグレーションスクリプトに以下のように、テーブル名、追加するカラム名、型名を追加する。
db\migrate\20180927130034_alter_members1.rb
class AlterMembers1 < ActiveRecord::Migration[5.2]
  def change
    add_column :members, :password_digest, :string
  end
end
  • マイグレーションを実行する。
$ bin/rails db:migrate

クラスメソッドhas_secure_password

  • モデルに、クラスメソッドhas_secure_passwordを追加する。
app/models/member.rb
class Member < ApplicationRecord
  has_secure_password
  • これにより、Memberクラスにpasswordおよびpassword_confirmationという名前の2つの属性が定義される。

  • password属性に対する次ようなバリデーションが設定される。

    • レコードの挿入時には、パスワードが空ではいけない。
    • パスワードの長さは72文字以下。
    • パスワードと確認用パスワードは一致すること。
  • これらのバリデーションを無効にした場合は、以下のようにvalidationオプションをfalseに設定する。

has_secure_password validation: false
  • 開発用のシードデータを修正する。
rb/seeds/development/members.rb
(省略)
    password: "asagao!",
    password_confirmation: "asagao!"
  )
end
  • データベースをリセットする。
$ bin/rails db:rebuild

ユーザーの認証

authenticateメソッド

  • member = Member.firstで1行取得する。
  • member.authenticate("detarame")で、パスワードが正しいか調べる。間違っているので、false。
  • member.authenticate("asagao!")は正しいので、1行返ってくる。
irb(main):003:0> member = Member.first
  Member Load (0.3ms)  SELECT  "members".* FROM "members" ORDER BY "members"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<Member id: 1, number: 10, name: "Taro", full_name: "佐藤 太郎", email: "Taro@example.com", birthday: "1981-12-01", sex: 1, administrator: true, created_at: "2018-09-27 13:16:20", updated_at: "2018-09-27 13:16:20", password_digest: "$2a$10$ShhumBcGJozj0uAYD7WU1.1Ul0bj1YS3l6rLuwLygJV...">
irb(main):004:0> member.authenticate("detarame")
=> false
irb(main):005:0> member.authenticate("asagao!")
=> #<Member id: 1, number: 10, name: "Taro", full_name: "佐藤 太郎", email: "Taro@example.com", birthday: "1981-12-01", sex: 1, administrator: true, created_at: "2018-09-27 13:16:20", updated_at: "2018-09-27 13:16:20", password_digest: "$2a$10$ShhumBcGJozj0uAYD7WU1.1Ul0bj1YS3l6rLuwLygJV...">
irb(main):006:0>

SessionsControllerの作成

  • Sessionsコントローラに、create、destroyアクションを追加。
config/routes.rb(一部)
(省略)
  resource :session, only: [:create, :destroy]
end
  • sessions_controller.rbの作成。
$ bin/rails g controller sessions
  • SessionsControllerの実装
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def create
    member = Member.find_by(name: params[:name])
    if member&.authenticate(params[:password])
      session[:member_id] = member.id
    else
      flash.alert = "名前とパスワードが一致しません"
    end
    redirect_to :root
  end

  def destroy
    session.delete(:member_id)
    redirect_to :root
  end
end

current_memberメソッドの定義

  • 現在ログインしている情報を取得するメソッドを作成。
  • helper_methodで登録することにより、テンプレートの中で使うことができる。
app/controllers/sessions_controller.rb
class ApplicationController < ActionController::Base
  private def current_member
    Member.find_by(id: session[:member_id]) if session[:member_id]
  end
  helper_method :current_member
end

ログインフォームの実装

  • 上部に、flash.alertの表示欄を追加。
  • 次に、全体をform_tagで囲むように修正。
  • ユーザー名、パスワードにname属性を追加。
app/views/shared/_login_form.html.erb
<h2>ログイン</h2>
<% if flash.alert %><p class="alert"><%= flash.alert %></p><% end %>
<%= form_tag :session, id: "login-form" do %>
    <div>
      <label>ユーザー名:</label>
      <input type="text" name="name">
    </div>
    <div>
      <label>パスワード:</label>
      <input type="password" name="password">
    </div>
    <div>
      <input type="submit" value="ログイン">
    </div>
  </form>
<% end %>
  • ログインしている場合は、サイドバー上部にログインフォームを表示しないようunless current_memberを追加する。
app/views/shared/_sidebar.html.erb(一部)
<%= render "shared/login_form" unless current_member %>

<h2>最新ニュース</h2>
(省略)
  • ログイン成功後

image.png

  • ログイン失敗

image.png

参考
改訂4版 基礎 Ruby on Rails (IMPRESS KISO SERIES)

1
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?