第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 開発環境でデバッグ情報表示
.
.
<%= yield %>
<%= render 'layouts/footer' %>
<%= debug(params) if Rails.env.development? %>
</div>
</body>
</html>
このように記述することで、開発環境のみでページ下にデバッグが可能になる。
###2 リソース
.
.
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) |
index
とcreate
の名前付きルートが同じだが、new
アクションの後にPOSTリクエストが送られたらuser_path
では、create
アクションが呼ばれるようになっている。
また、値をデータベースに追加・更新する際はそれぞれnew/createアクションと、edit/updateアクションがあるが、どちらも前者のGET
リクエストで、ページ表示、後者のPOST
/PATCH
リクエストで、追加・更新を行い、成功したらshow.html.erb
にリダイレクトされる。
つまり、DELETE
含め、GET
メソッド以外のアクション.html.erbファイルが作られることはない。(RESTfulではないということになる)
そもそもGET
がページを取得すると、第3章で勉強済みのため、よくよく考えたら当然のことなんだろうけど。。💦
###3 debuggerメソッド
byebug
gemを追加することで、下のようにdebugger
メソッドが使用できるようになる。
.
.
def show
@user = User.find(params[:id])
debugger
end
.
.
こうすることで、実際にアクションが実行された時、コンソールからデバッグしたい変数等を入力すると中身を確認することができる!
####4 Gravatar画像設定
Gravatarはプロフィール画像を自動で設定してくれる。(正確には違う)
特に最初のユーザー登録時に、画像設定されていないことによるトラブルを回避してくれるから便利!
GravatarのURLは、メールアドレスをMD5という仕組みでハッシュ化しているので、下のように設定することで使用することが可能になる
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
.
.
<%= gravatar_for @user %>
.
###5 form_withヘルパー
確かRails5あたりで、form_for / form_tag といった別のヘルパーが使われていたが、現在はform_withが推奨らしい。
今回はこの3つの違いではなく、form_withヘルパー内で生成される中身をHTMLソースと見比べて学んだことについてまとめる。
.
.
<%= 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タグでは、actionとmethod属性
actionで設定されている**/usersは、formがhttps://~~~.com/users
へ飛ぶということ。
( 2 リソース で、create
アクションに対応するURLが/users
であったことからも理解できる)
methodのpost**は、文字通りPOST
リクエストを送信するということ
そしてinputタグでは、nameとtype属性
nameで設定された値がparamsで渡される。
typeで値の種類を設定しておくと、例えばpasswordの入力時に、実際の値が見えないようになるなど、最適化してくれる。
###6 ストロングパラメーター
ここまでの実装方法だと、paramsで渡ってくる予定以外の値も、渡ってきた場追加してしまう。例えば管理者かどうかのadmin
属性を簡単にいじることが出来てしまうらしい。。💦
それを防ぐために、下のようにprivateメソッドで、paramsから渡ってくる値の種類に制限をかける。
.
.
.
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メソッドを使う)
<% 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 ユーザー登録成功時のテスト
今回一番勉強になったテストコードを掲載
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
流れは、
- GETリクエストで、signup_pathに当たるビューを表示
- 適切なユーザーが登録され、
User.count
が1増えることをチェック -
create
に成功したことで、適切に/users/show
が表示されているかチェック
特にassert_difference
とfollow_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と、デフォルトのWEBrick
Webサーバーより多数のリクエストを捌くことができるPumaサーバーを組み込んでデプロイする。
まずは本番環境でSSLを使うよう、1行追加する
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以降、デフォルトでPuma
gemが追加されている
次に設定ファイルを記述していくが、Pumaのドキュメントのコードそのままの引用で、理解していなくても大丈夫とのこと。
# 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と同じ階層に作成)
web: bundle exec puma -C config/puma.rb
最後に、本番データベース(PostgreSQL)を明示的に設定する(明示的に設定することを推奨されているらしい・・)
.
.
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にまとめるところまでやり切るのが大変になってきた。
でも書くことにも慣れてきて、前半の記事より少しは役に立つ記事になってきただろうか💦
アウトプットすることで、学びを再確認できることは実感中。。