0
0

More than 3 years have passed since last update.

Rails チュートリアル 第7章 備忘録

Last updated at Posted at 2020-12-26

第7章の備忘録です。

環境

Rails 6.0.3
Ruby 2.6.3

目次

1 開発環境でデバッグ情報表示
2 リソース
3 debuggerメソッド
4 Gravatar画像設定
5 form_withヘルパー
6 ストロングパラメーター
7 パーシャルでエラーメッセージ表示
8 ユーザー登録成功時のテスト
9 SSLとPumaの設定込みのデプロイ方法

1 開発環境でデバッグ情報表示

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

このように記述することで、開発環境のみでページ下にデバッグが可能になる。

2 リソース

config/routes.rb
.
.
  resources :users
end

この1行を追加すると、URLを生成するための多数の名前付きルートと共に、RESTfulなリソースで必要な全てのアクションが設定される。

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)
PATCH /users/1 update user_path(user)
DELETE /users/1 destroy user_path(user)

indexcreateの名前付きルートが同じだが、newアクションの後にPOSTリクエストが送られたらuser_pathでは、createアクションが呼ばれるようになっている。

また、値をデータベースに追加・更新する際はそれぞれnew/createアクションと、edit/updateアクションがあるが、どちらも前者のGETリクエストで、ページ表示、後者のPOST/PATCHリクエストで、追加・更新を行い、成功したらshow.html.erbにリダイレクトされる。

つまり、DELETE含め、GETメソッド以外のアクション.html.erbファイルが作られることはない。(RESTfulではないということになる)

そもそもGETページを取得すると、第3章で勉強済みのため、よくよく考えたら当然のことなんだろうけど。。💦

3 debuggerメソッド

byebuggemを追加することで、下のようにdebuggerメソッドが使用できるようになる。

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

こうすることで、実際にアクションが実行された時、コンソールからデバッグしたい変数等を入力すると中身を確認することができる!

4 Gravatar画像設定

Gravatarはプロフィール画像を自動で設定してくれる。(正確には違う)
特に最初のユーザー登録時に、画像設定されていないことによるトラブルを回避してくれるから便利!
GravatarのURLは、メールアドレスをMD5という仕組みでハッシュ化しているので、下のように設定することで使用することが可能になる

app/helpers/users_helper.rb
module UsersHelper
  # 引数で与えられたユーザーのGravatar画像を返す
  # 後の演習での、キーワード引数(size: 80)込み
  def gravatar_for(user, size: 80)
    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
app/views/users/show.html.erb
.
.
  <%= gravatar_for @user %>
.

5 form_withヘルパー

確かRails5あたりで、form_for / form_tag といった別のヘルパーが使われていたが、現在はform_withが推奨らしい。
今回はこの3つの違いではなく、form_withヘルパー内で生成される中身をHTMLソースと見比べて学んだことについてまとめる。

app/views/users/new.html.erb
.
.
<%= form_with(model: @user, local: true) do |f| %>
      <%= f.label :name %>
      <%= f.text_field :name %>
      .
      .
      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation %>

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

下がヘルパーで生成されたHTMLソース

<form accept-charset="UTF-8" action="/users" class="new_user"
      id="new_user" method="post">
  <input name="authenticity_token" type="hidden"
         value="NNb6+J/j46LcrgYUC60wQ2titMuJQ5lLqyAbnbAUkdo=" />
  <label for="user_name">Name</label>
  <input id="user_name" name="user[name]" type="text" />

  .
  .

  <label for="user_password_confirmation">Confirmation</label>
  <input id="user_password_confirmation"
         name="user[password_confirmation]" type="password" />

  <input class="btn btn-primary" name="commit" type="submit"
         value="Create my account" />
</form>

ここで着目したいのが、
formタグでは、actionmethod属性

actionで設定されている/usersは、formがhttps://~~~.com/usersへ飛ぶということ。
2 リソース で、createアクションに対応するURLが/usersであったことからも理解できる)
methodpostは、文字通りPOSTリクエストを送信するということ

そしてinputタグでは、nametype属性

nameで設定された値がparamsで渡される。
typeで値の種類を設定しておくと、例えばpasswordの入力時に、実際の値が見えないようになるなど、最適化してくれる。

6 ストロングパラメーター

ここまでの実装方法だと、paramsで渡ってくる予定以外の値も、渡ってきた場追加してしまう。例えば管理者かどうかのadmin属性を簡単にいじることが出来てしまうらしい。。💦

それを防ぐために、下のようにprivateメソッドで、paramsから渡ってくる値の種類に制限をかける。

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

  private

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

こうすることで先ほど例にあげた、admin属性が不正に含まれていた場合でも、適切に弾かれてエラーが発生する!

7 パーシャルでエラーメッセージ表示

ユーザー登録時、エラー内容がフォーム付近に表示されたらユーザーにとって優しい!!
ということで、下のようなパーシャルを作っておき、フォームに加える(renderメソッドを使う)

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

any?メソッドは、empty?メソッドの逆の意味を持ち、エラーが含まれているとtrueを返す。

またpluralizeメソッドは、第一引数の値によって、第二引数に設定した文字を単数/複数形に自動に変化させて表示してくれる便利機能!

8 ユーザー登録成功時のテスト

今回一番勉強になったテストコードを掲載

test/integration/users_signup_test.rb
require 'test_helper'

class UsersSignupTest < ActionDispatch::IntegrationTest
  .
  .
  .
  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
end

流れは、
1. GETリクエストで、signup_pathに当たるビューを表示
2. 適切なユーザーが登録され、User.countが1増えることをチェック
3. createに成功したことで、適切に/users/showが表示されているかチェック

特にassert_differencefollow_redirect!に注目!

assert_differenceメソッドは、do~endの処理後に、第一引数で設定した変数の数が、第二引数で設定した値分変化したかどうかをチェックすることが可能。
反対に、不適切なユーザーを登録せずに、User.countが増減していないことを確認するには、assert_no_differenceメソッドを使う。

follow_redirect!メソッドは、POSTリクエストを送信した結果を見て、指定されたリダイレクト先に移動するメソッドであり、今回の場合、createアクションでPOSTリクエストを送信したので、ユーザーが登録成功した場合、/users/showが表示されるはずである。
その意味を含めたメソッドであり、次のassert_template 'users/show'で表示されているかを実際に確認している。

9 SSLとPumaの設定込みのデプロイ方法

この章で実際にデータベースにCRUD操作が加わったことで、しっかりとしたセキュリティを考えなければならない。
そこで今回は、情報を暗号化するSSLと、デフォルトのWEBrickWebサーバーより多数のリクエストを捌くことができるPumaサーバーを組み込んでデプロイする。

まずは本番環境でSSLを使うよう、1行追加する

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

Herokuのサブドメインの場合は、遠隔にあるサーバーのSSLセットアップも記述した設定のみで可能である。
ただし、独自ドメインの場合は、SSL証明書を購入する必要がある。。。

次にPumaの設定だが、まず、
Rails5以降、デフォルトでPumagemが追加されている
次に設定ファイルを記述していくが、Pumaのドキュメントのコードそのままの引用で、理解していなくても大丈夫とのこと。

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

次に、ProcfileにHeroku上でPumaのプロセスを走らせる設定ファイルを作成する。(Gemfileと同じ階層に作成)

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

最後に、本番データベース(PostgreSQL)を明示的に設定する(明示的に設定することを推奨されているらしい・・)

config/database.yml
.
.
test:
  <<: *default
  database: db/test.sqlite3

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'] %>

以上で第7章終了。
だんだん1日でQiitaにまとめるところまでやり切るのが大変になってきた。
でも書くことにも慣れてきて、前半の記事より少しは役に立つ記事になってきただろうか💦
アウトプットすることで、学びを再確認できることは実感中。。

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