1
0

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 3 years have passed since last update.

Railsチュートリアル(第6版) 第7章 ユーザー登録

Posted at

#ユーザー登録
いよいよユーザーの登録ページに入っていく。
ユーザーを登録するさいのフォームに画像やサイドバー、成功時と失敗時のメッセージ、ストロングパラメーターなど覚えることはたくさんある。

##ユーザーを表示する
まずは、ユーザーの名前とプロフィール写真を表示するためのページを作る。

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

こんなかんじ

ではブランチをつくる
$ git checkout -b sign-up

###デバッグとRails環境
debugメソッドとparams変数を追記

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  .
  .
  .
  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <%= yield %>
      <%= render 'layouts/footer' %>
      <%= debug(params) if Rails.env.development? %>
    </div>
  </body>
</html>

if Rails.env.development?
これをいれておけば、開発環境だけデバッグ情報が表示されるようになる。
本番のアプリでは挿入されないのでOK

・Railsの3つの環境
 ・テスト環境(test)
 ・開発環境(development)
 ・本番環境(production)
開発環境にだけデバッグ情報があればOK

  $ rails console
  Loading development environment
  >> Rails.env
  => "development"
  >> Rails.env.development?
  => true
  >> Rails.env.test?
  => false

Railsオブジェクトに対し、envという属性を使えば、論理値(boolean)を取れる。

  $ rails console test
  Loading test environment
  >> Rails.env
  => "test"
  >> Rails.env.test?
  => true

他の環境でconsoleを実行する必要が生じた場合は、環境をパラメータとしてconsoleに渡せる。

$ rails server --environment production

明示的に他の環境を実行できる。

$ rails db:migrate RAILS_ENV=production

本番環境で本番データベースを作成できる。

  $ heroku run rails console
  >> Rails.env
  => "production"
  >> Rails.env.production?
  => true

Herokuの本番環境を確認できる。

デバッグ出力を整形する。

app/assets/stylesheets/custom.scss
@mixin box_sizing {
  -moz-box-sizing:    border-box;
  -webkit-box-sizing: border-box;
  box-sizing:         border-box;
}
.
.
.
/* miscellaneous */

.debug_dump {
  clear: both;
  float: left;
  width: 100%;
  margin-top: 45px;
  @include box_sizing;
}

Sassのミックイン機能を利用。
ミックスイン機能を使えば、CSSルールをパッケージ化して、複数の要素に適用できる。

.debug_dump {
  .
  .
  .
  @include box_sizing;
}

@includeを使えば下のような形で実行される。

.debug_dump {
  .
  .
  .
  -moz-box-sizing:    border-box;
  -webkit-box-sizing: border-box;
  box-sizing:         border-box;
}

image.png
画面下の方にデバッグ情報が出た。

コントローラーとアクションが書いてあり、これはparamsに含まれている内容で、YAMLという形式で書かれている。
YAMLは基本的にハッシュで構成されている。

演習

image.png
aboutページのやつ

###Usersリソース
RESTアーキテクチャの慣習に倣い、HTTP標準の作成、表示、更新、削除をリソースとして扱う。
HTTP標準には4つの基本操作POST、GET、PATCH、DELETEが定義される。

リソース名/idとすれば、そのユーザーを参照できる。
/users/1このような形

まだルーティング未定義なのでエラーになる。

resources :usersconfig/routes.rbに追加する。

HTTPリクエスト URL アクション 名前付きルート 用途
GET /users index users_path すべてのユーザーを一覧するページ
GET /users/1 show user_path(user) 特定のユーザーを表示するページ
GET /users/new new new_user_path ユーザーを新規作成するページ(ユーザー登録)
POST /users create users_path ユーザーを作成するアクション
GET /users/1/edit edit edit_user_path(user) id=1のユーザーを編集するページ
PATCH /users/1 update user_path(user) ユーザーを更新するアクション
DELETE /users/1 destroy user_path(user) ユーザーを削除するアクション

resources :usersを追加しただけで、RESTfulなルートがあっという間に構築できるので大変便利

次にやることは、ビューに表示するための埋め込みRubyの記述(仮)

app/views/users/show.html.erb
<%= @user.name %>, <%= @user.email %>

Usersコントローラー内に上記のshowページに対するたくしょんを追加し、@user変数を定義する。

app/controllers/users_controller.rb
  def show
    @user = User.find(params[:id])
  end

params[:id]の部分は、/users/1の1の部分に該当し、**findメソッドの引数に渡すことで文字列型から整数型に変換される。** idが1なら、User.find(1)`と同じ。

image.png

showページに行き、idを確認すると「1」となっていることが分かる。
id: 1は、params[:id]によって/users/:idから取得したもの
また、actionはshowで、controllerはusersとなっている。

演習

image.png

<%= @user.created_at %><br>
<%= @user.updated_at %>
<%= Time.now %>

###debuggerメソッド
debugメソッドでデバッグ情報をみる事ができた。
さらに直感的に分かるよう、byebuggemによるdebuggerメソッドを、アプリケーションに入れることで、debuggerが読まれた時点のデバッグ情報をみることができる。

こんな感じで、debuggerを差し込んだ時点で止まる。

Processing by UsersController#show as HTML
  Parameters: {"id"=>"1"}
  User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/users_controller.rb:4:in `show'
Return value is: nil

[1, 10] in /home/ubuntu/environment/sample_app/app/controllers/users_controller.rb
    1: class UsersController < ApplicationController
    2:   
    3:   def show
    4:     @user = User.find(params[:id])
    5:     debugger
=>  6:   end
    7:   
    8:   def new
    9:   end
   10: end
(byebug) 

Ctrl-Dを押すと抜け出せる。
デバッグしたいところに差し込むので、終わったらdebuggerは削除しよう。

###Gravatar画像とサイドバー
Q:Gravatarとは?
A:Gravatar(Globally Recognized AVATAR)の略。無料サービスで写真とメールアドレスの紐づけができる。

おかげさまで、写真のアップロードする時の面倒さ作業が画像の置き場所の悩みを解決できる。

gravatar_forヘルパーメソッドを使って画像を利用できるようにする。

app/views/users/show.html.erb
<% provide(:title, @user.name) %>
<h1>
  <%= gravatar_for @user %>
  <%= @user.name %>
</h1>

ヘルパーファイルで定義されているメソッドは自動的にすべてのビューで利用できるということで、利便性を考えて、gravatar_forをUsersコントローラーに結び付けれたヘルパーファイルに置くことにする。

app/helpers/users_helper.rb
module UsersHelper

  # 引数で与えられたユーザーのGravatar画像を返す
  def gravatar_for(user)
    gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
    gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
    image_tag(gravatar_url, alt: user.name, class: "gravatar")
  end
end

Rubyでは、Digestライブラリのhexdigestメソッドを使うと、MD5のハッシュ化が可能となる。
メールアドレスは、大文字と小文字を区別しないが、MD5ハッシュは大文字と小文字を区別する。なので、downcaseメソッドを使って、hexdigestの引数を小文字に変換する。
(コールバック処理で小文字に変換されたメールアドレスを利用しているため、ここの小文字変換はなくても結果は同様だが、将来gravatar_forメソッドが別の場所から呼ばれた際に有意義となる)

image.png
画像が表示された。

こんどはレイアウトを変える

app/views/users/show.html.erb
<% provide(:title, @user.name) %>
<div class="row">
  <aside class="col-md-4">
    <section class="user_info">
      <h1>
        <%= gravatar_for @user %>
        <%= @user.name %>
      </h1>
    </section>
  </aside>
</div>

CSSも手を加える。

app/assets/stylesheets/custom.scss
/* sidebar */

aside {
  section.user_info {
    margin-top: 20px;
  }
  section {
    padding: 10px 0;
    margin-top: 20px;
    &:first-child {
      border: 0;
      padding-top: 0;
    }
    span {
      display: block;
      margin-bottom: 3px;
      line-height: 1;
    }
    h1 {
      font-size: 1.4em;
      text-align: left;
      letter-spacing: -1px;
      margin-bottom: 3px;
      margin-top: 0px;
    }
  }
}

.gravatar {
  float: left;
  margin-right: 10px;
}

.gravatar_edit {
  margin-top: 15px;
}

左に寄った。
image.png

##ユーザー登録フォーム
プロフィールページが動いたので、ユーザー登録フォームを作る。

###form_withを使用する
フォームを読み込むには、form_withヘルパーメソッドを使い、Active Recordのオブジェクトを取り込んで、そのオブジェクトの属性からフォームを構築するもの。

newアクションで必要となる@user変数の定義をする。

app/controllers/users_controller.rb
  def new
    @user = User.new
  end

erbとscssも変更する。

app/views/users/new.html.erb
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_with(model: @user, local: true) do |f| %>
      <%= f.label :name %>
      <%= f.text_field :name %>

      <%= f.label :email %>
      <%= f.email_field :email %>

      <%= f.label :password %>
      <%= f.password_field :password %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation %>

      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>
app/assets/stylesheets/custom.scss
/* forms */

input, textarea, select, .uneditable-input {
  border: 1px solid #bbb;
  width: 100%;
  margin-bottom: 15px;
  @include box_sizing;
}

input {
  height: auto !important;
}

ユーザーフォームの画面ができた。
image.png

演習の解答
foobarはメタ構文変数なので意味がない。メタ構文変数とは意味のないただの文字。何かテストユーザーを作るときの田中太郎とか花子とかそんな感じ
また、formの頭文字を取ったものとしてfは分かりやすい。

###フォームHTML
フォームを理解するために、form_withって何かを理解する。
(以前のrailsでは、form_forだったけど、新しいrailsではform_withになっている。詳しくは調べてください)

<%= form_with(model: @user, local: true) do |f| %>
  .
<% end %>

doキーワードは、form_with1つの変数を持つブロックを取るということ

・ハッシュ引数のlocal: trueとすることで、Ajaxをオフにできる。Ajaxをオンにするには、remote: true

fオブジェクトは、HTMLフォーム要素に対応するメソッドが呼びされたとき、@user属性を設定するために設計されたHTMLを返す。例えば、、、

<%= f.label :name %>
<%= f.text_field :name %>

とすることで、name属性を設定するラベル付きテキストフィール要素を作るHTMLを作成する。
従って、下のようなHTMLを生成することになる。

<label for="user_name">Name</label>
<input id="user_name" name="user[name]" type="text" />

type="text"type="email"type="password"の違い
 ・type="text"は、内容をそのまま表示
 ・type="email"は、モバイル端末の入力フォームにて、最適化されたキーボードが表示される。
 ・type="password"は、セキュリティ上文字が隠蔽される。

inputタグのname属性を使って、初期化したハッシュをparams変数経由で構成する。

formタグを作成する際、@userオブジェクトを使うが、ユーザーが新しいユーザーかどうかで処理が分かれる。今回、@userは新しいユーザーなので、postメソッドを使うと判断する。

<form action="/users" class="new_user" id="new_user" method="post">

上で大事なのは、action="/users"method="post"の部分になる。/usersに対して、postリクエストを送信する。

formタグの内側では下のようなHTMLが生成されている。

<input name="authenticity_token" type="hidden"
       value="NNb6+J/j46LcrgYUC60wQ2titMuJQ5lLqyAbnbAUkdo=" />

これは、CSRF(Cross-Site Request Forgery)という攻撃を阻止するためのトークンを含めている。

##ユーザー登録失敗
無効なデータを送信した際にエラーの一覧がでるようにする。

###正しいフォーム
以前、resources :usersを追加したことで、RESTful URIに応答するようになった。
ということで、全体の流れとしては、、、

/signupページでフォームにデータが入る
usersコントローラーのcreateアクションでフォームのデータを受け取る
User.newで新しいユーザーオブジェクトを作成する
④ユーザーオブジェクトを保存する。保存できなかったら、renderで登録ページを表示する。

createアクション内で、新しいユーザーオブジェクトを作成する際、以下のような方法で行う。
@user = User.new(params[:user])
この[:user]は、paramsハッシュで各リクエスト情報が入っている。そして、このparamsは入れ子になっており、送られたデータ情報が含まれている。
このような感じに

"user" => { "name" => "Foo Bar",
            "email" => "foo@invalid",
            "password" => "[FILTERED]",
            "password_confirmation" => "[FILTERED]"
          }

Railsでは、文字列として渡すのではなく、params[:user]のようにシンボルとしてUsersコントローラーに渡している。
User.newの引数とハッシュの値は完全に一致する。
従って

@user = User.new(params[:user])

@user = User.new(name: "Foo Bar", email: "foo@invalid",
                 password: "foo", password_confirmation: "bar")

は同じであるということ。

しかし、マスアサインメントというのは、脆弱性があるため現在ではStrong Parametersを使うようになった。

###Storong Parameters
前回のコードにあった
@user = User.new(params[:user])
というものは、マスアサインメントの脆弱性があったため、Rails 4.0以降ではエラーを引き起こすようになった。
paramsハッシュ全体を初期化する行為は、セキュリティ上非常に危険なことだ。Userモデルにadmin属性というのがった際、admin=1という値をparams[:user]に紛れ込ませてしまえば、この属性をtrueにさせることができ、管理者権限を奪い取れてしまう。

こういった危険性を回避するため、Strong Parametersを使おうねってなった。これは、必須のパラメーター許可されたパラメーターを指定することができるもの。

この場合、paramsハッシュでは、:user属性を必須として、名前、メールアドレス、パスワード、パスワードの確認属性を許可して、それ以外を許可しないようにしたい。

params.require(:user).permit(:name, :email, :password, :password_confirmation)

こういったパラメーターを使いやすくするために、user_paramsという外部メソッドを使うのが慣例で、さらにこの外部メソッドは、privateの中に書くことで、外部からこのメソッドが使えないようにする。

app/controllers/users_controller.rb
class UsersController < ApplicationController
  .
  .
  .
  def create
    @user = User.new(user_params)
    if @user.save
      # 保存の成功をここで扱う。
    else
      render 'new'
    end
  end

  private

    def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end
end

まだこの時点では、間違ったデータを送信してもフィードバックがない。また、新しいユーザーが作成されることもない。
これらを次は解決する。

演習
image.png

###エラーメッセージ
現時点では、間違った値を送信した時のエラーメッセージが出ない。

$ rails console
>> user = User.new(name: "Foo Bar", email: "foo@invalid",
?>                 password: "dude", password_confirmation: "dude")
>> user.save
=> false
>> user.errors.full_messages
=> ["Email is invalid", "Password is too short (minimum is 6 characters)"]

errors.full_messagesオブジェクトは、エラーメッセージの配列を持っている。
このエラーメッセージのパーシャルをユーザーのnewページでパーシャル出力すればOK。
同時に、Bootstrapのform-controlというCSSクラスを追加すれば、良い感じにいなる。

app/views/users/new.html.erb
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_with(model: @user, local: true) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= f.label :name %>
      <%= f.text_field :name, class: 'form-control' %>

      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

<%= render 'shared/error_messages' %>というパーシャルからrenderするようにまとめている。
ので、作成する。
$ touch app/views/shared/_error_messages.html.erb
そして下記のものが、エラーメッセージのパーシャル。

app/views/shared/_error_messages.html.erb
<% if @user.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(@user.errors.count, "error") %>.
    </div>
    <ul>
    <% @user.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

user.errors.any?は、エラーが一つでもあれば、true
 user.errors.empty?は、逆の動作をする。

user.errors.countは、エラーの数をカウントする。

pluralizeというテキストヘルパーは、英語専用(複数形の時は語尾にsが付くやつ、、、)日本語だとないかな?日本語は数え方が変わるけど(一本、一冊、一人)

>> helper.pluralize(1, "error")
=> "1 error"
>> helper.pluralize(5, "error")
=> "5 errors"

なので、<%= pluralize(@user.errors.count, "error") %>とすれば、エラーの数を数えた数字を、第二引数のerrorにくっつけて、単数か複数かで単語を変える。

そして、エラーメッセージが出た時に赤く囲ってくれるようにCSSを追加

app/assets/stylesheets/custom.scss
#error_explanation {
  color: red;
  ul {
    color: red;
    margin: 0 0 30px 0;
  }
}

.field_with_errors {
  @extend .has-error;
  .form-control {
    color: $state-danger-text;
  }
}

image.png
エラーメッセージがでた。
しかし、Password can't be blankが2つあるので、後々修正する。

演習

image.png

###失敗時のテスト
テスト機能を持ったWebフレームワークがなかった時代では、フォームのテストを毎回手動で行っていた。
一つ一つページを表示して、値を入力して、、、みたいな地道な作業である。

Railsではフォーム用のテストを自動化できる。
なので、新規ユーザー登録用の統合テストを生成する。

$ rails generate integration_test users_signup

このテストでは、無効なユーザーを登録しようとした時に、作成されないことを確認する。

test/integration/users_signup_test.rb
require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name:  "",
                                         email: "user@invalid",
                                         password:              "foo",
                                         password_confirmation: "bar" } }
    end
    assert_template 'users/new'
  end
end

テスト概要
get signup_pathでユーザー登録ページにアクセス

assert_no_difference 'User.count' do登録前と登録後でユーザーの数が変わってないかチェック
下記のデータをpostして作成する。(下記のユーザー情報は検証に弾かれるものにする)

 post users_path, params: { user: { name:  "",
                                     email: "user@invalid",
                                     password:              "foo",
                                     password_confirmation: "bar" } }

③送信失敗時に、newアクションが再描画されるので、assert_template 'users/new'でエラーメッセージが表示されているかの確認

テストした結果OKだった。

演習
1.エラーメッセージに対するテストを追加

test/integration/users_signup_test.rb
require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest

  test "invalid signup information" do
    get signup_path
    assert_no_difference 'User.count' do
      post users_path, params: { user: { name:  "",
                                         email: "user@invalid",
                                         password:              "foo",
                                         password_confirmation: "bar" } }
    end
    assert_template 'users/new'
    assert_select   'div#error_explanation'                                       
    assert_select   'div.field_with_errors'
  end
end

##ユーザー登録成功
ここから、実際に新規ユーザーを登録できるようにしていく。
ユーザーが登録、保存できたら、ブラウザの表示を例ダイレクトして、登録されたユーザーのプロフィールページを表示する。

###登録フォームの完成
image.png

現状は正しいユーザー情報を入力しても、テンプレートがないと出る。
image.png

今回、Railsの慣習に倣い、ユーザー登録成功時にはページを描画せず、別のページにリダイレクトさせるようにする。
リダイレクト先は、ユーザーのプロフィールページにする。

app/controllers/users_controller.rb
  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to @user
    else
      render 'new'
    end
  end

redirect_to @userに関して
この辺り、学習まとめを作っている人の中で謎ポイントとしてよく取り上げられている気がする。
「なにこれ?よーわからん」的な

Railsチュートリアルの説明引用

これはredirect_to @userというコードから(Railsエンジニアが)user_url(@user)といったコードを実行したいということを、Railsが推察してくれた結果になります。

これ、Railsの省略の書き方を応用したもので、省略しまくった結果redirect_to @userになっている。

この方の説明が大変参考になった。
redirect_to @userが何を省略しているかわかりますか?〜挫折しないRailsチュートリアル7章〜

###flash
登録できたら、「登録完了」等のメッセージが欲しい。
ただし、2度目以降はそのページにメッセージを表示させない事。

これを可能にしてくれるのが、flashという特殊な変数。
この変数はハッシュのように扱える。

app/controllers/users_controller.rb
  def create
    @user = User.new(user_params)
    if @user.save
      flash[:success] = "Welcome to the Sample App!"
      redirect_to @user
    else
      render 'new'
    end
  end

flash[:success]に登録成功時のメッセージを格納する。

続いて、htmlにメッセージ表示を実装

app/views/layouts/application.html.erb
  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <% flash.each do |message_type, message| %>
        <div class="alert alert-<%= message_type %>"><%= message %> </div>
      <% end %>
      <%= yield %>
      <%= render 'layouts/footer' %>
      <%= debug(params) if Rails.env.development? %>
    </div>

alert-<%= message_type %>successとかdangerとかが入る。

演習
答え::successとか:dangerのシンボルを式展開すると:が除かれたものが出力される。

###実際のユーザー登録
一旦サンプルアプリケーションのユーザーをリセット
$ rails db:migrate:reset
そして、Webサーバーを再起動する。

サンプルユーザーとして
名前:Rails Tutorial
メールアドレス:example@railstutorial.org
で登録する。
image.png

再読み込みすると
image.png

演習

> User.find_by(email: "example@railstutorial.org")
   (0.4ms)  SELECT sqlite_version(*)
  User Load (1.6ms)  SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT ?  [["email", "example@railstutorial.org"], ["LIMIT", 1]]
 => #<User id: 1, name: "Rails Tutorial", email: "example@railstutorial.org", created_at: "2021-05-26 22:20:03", updated_at: "2021-05-26 22:20:03", password_digest: [FILTERED]> 

###成功時のテスト
前回は無効な値の送信時のテストだったが、今回はデータベースの中身が正しいかどうか検証する。
つまり、有効な情報でユーザーが作成できたかどうかをチェックする。

assert_difference 'User.count', 1 do
  post users_path, ...
end

このように書いてあげればよい。登録前と登録後でユーザーが一人増えてれば良いのだ。
成功時のテスト

test/integration/users_signup_test.rb
  test "valid signup information" do
    get signup_path
    assert_difference 'User.count', 1 do
      post users_path, params: { user: { name:  "Example User",
                                         email: "user@example.com",
                                         password:              "password",
                                         password_confirmation: "password" } }
    end
    follow_redirect!
    assert_template 'users/show'
  end

postリクエスト送信した時に、follow_redirect!というメソッドを使えば、リダイレクト先に遷移する。
そして、assert_template 'users/show'にとって、showアクションとshow.html.erbビューが正しく動作しているか確認している。
さらに、assert_template 'users/show'はページ全体のテストもしているので、この1行は大切だ。

演習
1.flashに対するテスト
assert_not flash.empty?あるいは、blank?を使っても良いと思う。

2.より読みやすいコードに変更。content_tagに変更
<%= content_tag(:div,message,class:"alert alert-#{message_type}") %>

##プロのデプロイ
ここにきてやっと、実際のデータを操作できるデプロイを行える。
ユーザー作成と保存ができる段階まで来た。

ここまでの段階をコミットし、masterにマージしておこう。

###本番環境でのSSL
ユーザー登録フォームで送信した名前やメールアドレス、パスワード等のデータが暗号化されていないとネットワーク越しに漏洩してしまうリスクがある。
そのため、Transport Layer Security(TLS)を使う。別称では、SSL(Secure Socket Layer)とも呼ばれる。

SSL有効かの手順は簡単
production.rbの設定ファイルを1行修正すればOK

config/environments/production.rb
Rails.application.configure do
  # Force all access to the app over SSL, use Strict-Transport-Security,
  # and use secure cookies.
  config.force_ssl = true  
end

また、本来であればドメイン毎にSSL証明書を購入するのだが、今回はHerokuのSSL証明書に便乗する。

###本番環境用のWebサーバー
Herokuのデフォルトでは、WEBrickというWebサーバーを使用しているが、トラフィックの増加に弱いので、今回はWEBrickからPumaサーバーに置き換える。
Pumaサーバーは多数のリクエストを捌けるので、本番環境に適している。

Rails5以降では、Pumaはデフォルトの設定で使えるため、Pumaの設定を書き込むだけでOK

config/puma.rb
# Pumaの設定ファイル
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count
port        ENV.fetch("PORT") { 3000 }
environment ENV.fetch("RAILS_ENV") { ENV['RACK_ENV'] || "production" }
pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }
workers ENV.fetch("WEB_CONCURRENCY") { 2 }
preload_app!
plugin :tmp_restart

最後に、Pumaのプロセスを走らせるProcfileと呼ばれる設定ファイルを作成する。

./Procfile
web: bundle exec puma -C config/puma.rb

###本番データベースを設定する
本番環境で使うデータベースは、PostgreSQL。(HerokuのRails6向けでは、PostgreSQLが推奨されているため)

config/database.yml
production:
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://railsguides.jp/configuring.html#データベース接続をプールする
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  database: sample_app_production
  username: sample_app
  password: <%= ENV['SAMPLE_APP_DATABASE_PASSWORD'] %>

あとは、デプロイすればOK

$ rails test
$ git add -A
$ git commit -m "Use SSL and the Puma webserver in production"
$ git push && git push heroku

演習
1.鍵マークの確認
image.png
鍵マークついているので、OK

#最後に
ユーザー登録機能の実装でいよいよWEBアプリケーションっぽくなってきた。
railsチュートリアルをやっている人なら、この章以降に難易度が着実に上がっていっていくという実感は湧くはず。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?