9 コード品質を上げる
雑感
この章はCIによる自動テストや静的解析、パフォーマンス検証などのアプリケーションコードの品質チェックを行う外部サービスの内容が主でした。
コミット前フックでのrubocop実行などは軽く紹介程度でしたが、業務で使えそうだったので少し本書の内容から拡張したバージョンのコードを作成してみました。
9.1 継続的インテグレーション
GitHub Actions の設定方法
GitHub Actions は GitHub 上にあるリポジトリでの変更を検知して自動でテストを実行してくれる Web サービス。
1. GitHub Actions の設定ファイルの作成
リポジトリ上部のActions
タブ > いずれかのSet up this workflow
ボタン(Ruby Gem
やRuby
など用途ごとに分かれているが設定ファイルを独自に変更する場合はどれを選んでも構わない)と進むと以下の yml ファイルの設定画面へ移行する。このファイルを編集・コミットすることで任意のテストを実施させる。同様の設定ファイルを.github/workflows/ruby.yml
としてリポジトリへ加えることでも利用可能。
私の場合、perfect-rails
というリポジトリの中に本書で扱っているアプリケーション全てをまとめているので、perfect-rails/awesome_events
内でのみテストを実施するために追加でワーキングディレクトリの指定もしています。
name: Rails Tests
on: [push, pull_request] # pushまたはPR作成時にトリガーされる
jobs: # この配下に実行する処理を記述
build:
runs-on: ubuntu-latest # 実行環境をubuntuに指定
+ defaults:
+ run:
+ working-directory: awesome_events # ここでワーキングディレクトリを指定
steps:
- uses: actions/checkout@v2
- name: Set up Ruby 2.7
uses: ruby/setup-ruby@v1 # ruby/setup-rubyモジュールを指定
with:
ruby-version: 2.7
+ working-directory: ./awesome_events # Rubyのセットアップディレクトリも指定
- name: Build and test
env:
RAILS_ENV: test
run: |
sudo apt-get -yqq install libsqlite3-dev
bundle install --jobs 4 --retry 3
bin/rails db:create
bin/rails db:migrate
bin/yarn install
bin/rails test
bin/rails test:system
2. システムテストを行うための設定
GitHub Actions でシステムテストを行うためにはheadless Chrome
を使うように設定する必要がある。
require "test_helper"
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400]
end
GitHub Actions で Elasticsearch とそのプラグインを使う
Elasticsearch をアプリケーションのロジックとして組み込んでいる場合は、テスト実行のためにGitHub Actions 上でも利用可能にする必要がある。
1. 作成するアクション用のリポジトリを作成
GitHub Actions 上でも Elasticsearch を利用するためには、Elasticsearch 環境を作るアクションを実装する必要がある。
アクションはパブリックリポジトリを作成してそこにファイルを置くだけで利用可能。
必要ファイルは下記となる。
- README.md
- Dockerfile
- action.yml
- run-elasticsearch.sh
作成例はElasticsearch 公式から提供されており、ほとんどがそのまま使用できるが、アプリケーションの仕様に応じて一部変更が必要な場合がある。
FROM docker:stable
RUN apk add --update bash
COPY run-elasticsearch.sh /run-elasticsearch.sh
ENTRYPOINT [ "/run-elasticsearch.sh" ]
action.yml
はAuthor
を自分に指定する。本書ではさらにプラグインの設定も追加しているが、こちらは公式ですでに追加対応済。
name: 'Run Elasticsearch'
description: 'This action spins up an Elasticsearch instance that can be accessed and used in your subsequent steps.'
+author: 'Saito-3815'
branding:
icon: 'database'
color: 'green'
inputs:
stack-version:
description: 'The version of the Elastic Stack you want to run'
required: true
security-enabled:
description: 'Enable or disable HTTPS, enabled by default'
default: 'true'
required: false
nodes:
description: 'Number of nodes in the cluster'
required: false
default: 1
port:
description: 'Port where you want to run Elasticsearch'
required: false
default: 9200
elasticsearch_password:
description: 'The password for the user elastic in your cluster'
required: false
default: 'changeme'
plugins:
description: 'Plugins that you want to include'
required: false
wait:
description: 'Number of seconds to wait after launch'
required: false
default: 10
network-name:
description: 'Name of the network to create with docker'
required: false
default: elastic
container-name:
description: 'Name for the container'
required: false
default: es
runs:
using: 'docker'
image: 'Dockerfile'
env:
STACK_VERSION: ${{ inputs.stack-version }}
NODES: ${{ inputs.nodes }}
PORT: ${{ inputs.port }}
PLUGINS: ${{ inputs.plugins }}
SECURITY_ENABLED: ${{ inputs.security-enabled }}
ELASTICSEARCH_PASSWORD: ${{ inputs.elasticsearch_password }}
WAIT: ${{ inputs.wait }}
NETWORK_NAME: ${{ inputs.network-name }}
CONTAINER_NAME: ${{ inputs.container-name }}
run-elasticsearch.sh
は指定されたプラグインをインストールするコマンドを組み立てる部分と、それを実行してインストールする部分を追加しています。(このファイルに関しては本書を見様見真似で作成しましたが、理解度が薄く冗長な記述となっているのでおそらくベストプラクティスではないと思います。一応、正常に動作はします。)
#!/bin/bash
set -euxo pipefail
if [[ -z $STACK_VERSION ]]; then
echo -e "\033[31;1mERROR:\033[0m Required environment variable [STACK_VERSION] not set\033[0m"
exit 1
fi
+PLUGIN_INSTALL_CMD=""
+PLUGINS_STR=`echo ${PLUGINS} | sed -e 's/\n/ /g'`
+if [ -n "$PLUGINS_STR" ]; then
+ ARRAY=(${PLUGINS_STR})
+ for i in "${ARRAY[@]}"
+ do
+ PLUGIN_INSTALL_CMD+="elasticsearch-plugin install --batch ${i} && "
+ done
+fi
MAJOR_VERSION=`echo ${STACK_VERSION} | cut -c 1`
NETWORK_NAME=${NETWORK_NAME:-elastic}
CONTAINER_NAME=${CONTAINER_NAME:-es}
SECURITY_ENABLED=${SECURITY_ENABLED:-true}
docker network inspect $NETWORK_NAME >/dev/null 2>&1 || docker network create $NETWORK_NAME
mkdir -p /es/plugins/
chown -R 1000:1000 /es/
if [[ ! -z $PLUGINS ]]; then
docker run --rm \
--user=0:0 \
--network=$NETWORK_NAME \
-v /es/plugins/:/usr/share/elasticsearch/plugins/ \
--entrypoint=/usr/share/elasticsearch/bin/elasticsearch-plugin \
docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} \
install ${PLUGINS/\\n/ } --batch
fi
for (( node=1; node<=${NODES-1}; node++ ))
do
port_com=$((9300 + $node - 1))
UNICAST_HOSTS+="es$node:${port_com},"
done
for (( node=1; node<=${NODES-1}; node++ ))
do
port=$((PORT + $node - 1))
port_com=$((9300 + $node - 1))
if [ "x${MAJOR_VERSION}" == 'x6' ]; then
docker run \
--rm \
--env "node.name=${CONTAINER_NAME}${node}" \
--env "cluster.name=docker-elasticsearch" \
--env "cluster.routing.allocation.disk.threshold_enabled=false" \
--env "bootstrap.memory_lock=true" \
--env "ES_JAVA_OPTS=-Xms1g -Xmx1g" \
--env "xpack.security.enabled=false" \
--env "xpack.license.self_generated.type=trial" \
--env "discovery.zen.ping.unicast.hosts=${UNICAST_HOSTS}" \
--env "discovery.zen.minimum_master_nodes=${NODES}" \
--env "http.port=${port}" \
--ulimit nofile=65536:65536 \
--ulimit memlock=-1:-1 \
--publish "${port}:${port}" \
--publish "${port_com}:${port_com}" \
--detach \
--network=$NETWORK_NAME \
--name="${CONTAINER_NAME}${node}" \
-v /es/plugins/:/usr/share/elasticsearch/plugins/ \
docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} \
+ /bin/sh -vc "${PLUGIN_INSTALL_CMD} /usr/local/bin/docker-entrypoint.sh"
elif [ "x${MAJOR_VERSION}" == 'x7' ]; then
docker run \
--rm \
--env "node.name=${CONTAINER_NAME}${node}" \
--env "cluster.name=docker-elasticsearch" \
--env "cluster.initial_master_nodes=es1" \
--env "discovery.seed_hosts=es1" \
--env "cluster.routing.allocation.disk.threshold_enabled=false" \
--env "bootstrap.memory_lock=true" \
--env "ES_JAVA_OPTS=-Xms1g -Xmx1g" \
--env "xpack.security.enabled=false" \
--env "xpack.license.self_generated.type=trial" \
--env "http.port=${port}" \
--env "action.destructive_requires_name=false" \
--ulimit nofile=65536:65536 \
--ulimit memlock=-1:-1 \
--publish "${port}:${port}" \
--detach \
--network=$NETWORK_NAME \
--name="${CONTAINER_NAME}${node}" \
-v /es/plugins/:/usr/share/elasticsearch/plugins/ \
docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} \
+ /bin/sh -vc "${PLUGIN_INSTALL_CMD} /usr/local/bin/docker-entrypoint.sh"
elif [ "x${MAJOR_VERSION}" == 'x8' ] || [ "x${MAJOR_VERSION}" == 'x9' ]; then
if [ "${SECURITY_ENABLED}" == 'true' ]; then
elasticsearch_password=${ELASTICSEARCH_PASSWORD-'changeme'}
docker run \
--rm \
--env "ELASTIC_PASSWORD=${elasticsearch_password}" \
--env "xpack.license.self_generated.type=trial" \
--env "node.name=${CONTAINER_NAME}${node}" \
--env "cluster.name=docker-elasticsearch" \
--env "cluster.initial_master_nodes=es1" \
--env "discovery.seed_hosts=es1" \
--env "cluster.routing.allocation.disk.threshold_enabled=false" \
--env "bootstrap.memory_lock=true" \
--env "ES_JAVA_OPTS=-Xms1g -Xmx1g" \
--env "http.port=${port}" \
--env "action.destructive_requires_name=false" \
--ulimit nofile=65536:65536 \
--ulimit memlock=-1:-1 \
--publish "${port}:${port}" \
--network=$NETWORK_NAME \
--name="${CONTAINER_NAME}${node}" \
--detach \
-v /es/plugins/:/usr/share/elasticsearch/plugins/ \
docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} \
+ /bin/sh -vc "${PLUGIN_INSTALL_CMD} /usr/local/bin/docker-entrypoint.sh"
else
docker run \
--rm \
--env "xpack.security.enabled=false" \
--env "node.name=${CONTAINER_NAME}${node}" \
--env "cluster.name=docker-elasticsearch" \
--env "cluster.initial_master_nodes=es1" \
--env "discovery.seed_hosts=es1" \
--env "cluster.routing.allocation.disk.threshold_enabled=false" \
--env "bootstrap.memory_lock=true" \
--env "ES_JAVA_OPTS=-Xms1g -Xmx1g" \
--env "xpack.license.self_generated.type=trial" \
--env "http.port=${port}" \
--env "action.destructive_requires_name=false" \
--ulimit nofile=65536:65536 \
--ulimit memlock=-1:-1 \
--publish "${port}:${port}" \
--network=$NETWORK_NAME \
--name="${CONTAINER_NAME}${node}" \
--detach \
-v /es/plugins/:/usr/share/elasticsearch/plugins/ \
docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} \
+ /bin/sh -vc "${PLUGIN_INSTALL_CMD} /usr/local/bin/docker-entrypoint.sh"
fi
fi
done
if ([ "x${MAJOR_VERSION}" == 'x8' ] || [ "x${MAJOR_VERSION}" == 'x9' ]) && [ "${SECURITY_ENABLED}" == 'true' ]; then
docker run \
--network $NETWORK_NAME \
--rm \
appropriate/curl \
--max-time 120 \
--retry 120 \
--retry-delay 1 \
--retry-connrefused \
--show-error \
--silent \
-k \
-u elastic:${ELASTICSEARCH_PASSWORD-'changeme'} \
https://${CONTAINER_NAME}1:$PORT
else
docker run \
--network $NETWORK_NAME \
--rm \
appropriate/curl \
--max-time 120 \
--retry 120 \
--retry-delay 1 \
--retry-connrefused \
--show-error \
--silent \
http://${CONTAINER_NAME}1:$PORT
fi
sleep $WAIT
echo "Elasticsearch up and running"
作成後はrun-elasticsearch.sh
に実行権限を付与しておく。
% chmod a+x run-elasticsearch.sh
全て完了したら、v1 タグをつけてコミットし、リポジトリへプッシュする。
# 通常通りコミットを作成
git add .
git commit -m "add: GitHub Actions用の設定ファイルを追加"
# コミットにタグを付ける
git tag v1
2. アプリケーションの CI を実行する GitHub Actions を Elasticsearch のアクションを呼びだして実行する
Elasticsearch 用のアクションを作成した後にアプリケーションのテストを実行する GitHub Actions の設定ファイルへそのアクションを利用する記述を追加する。
このファイルを追加してコミットし、GitHub へプッシュすると GitHub Actions でワークフローが実行される。
name: Rails Tests
on: [push, pull_request] # pushまたはPR作成時にトリガーされる
jobs: # この配下に実行する処理を記述
build:
runs-on: ubuntu-latest # 実行環境をubuntuに指定
defaults:
run:
working-directory: awesome_events # ここでワーキングディレクトリを指定
steps:
- uses: actions/checkout@v2
- name: Set up Ruby 2.7
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
working-directory: ./awesome_events # Rubyのセットアップディレクトリも指定
+ # ElasticsearchをGitHub Actions上で利用するための設定
+ - name: Configure sysctl limits
+ run: |
+ sudo swapoff -a
+ sudo sysctl -w vm.swappiness=1
+ sudo sysctl -w fs.file-max=262144
+ sudo sysctl -w vm.max_map_count=262144
+ - name: Run Elasticsearch
+ # リポジトリ名@タグ名で作成したアクションのリポジトリを指定できる
+ # タグ名はブランチ名としても良い
+ uses: perfect-ruby-on-rails/elasticsearch-with-plugins-action@v1
+ with:
+ stack-version: 7.6.0
+ plugins: |
+ analysis-kuromoji
- name: Build and test
env:
RAILS_ENV: test
run: |
sudo apt-get -yqq install libsqlite3-dev
bundle install --jobs 4 --retry 3
bin/rails db:create
bin/rails db:migrate
bin/yarn install
bin/rails runner 'Event.search_index.delete rescue nil'
bin/rails runner 'Event.reindex'
bin/rails test
bin/rails test:system
9.2 Gem の定期 update
gem のアップデートは定期的に手動で実行する場合と、利用するライブラリを定期更新する GitHub Dependabot などのサービスを使用する方法がある。
dependabot の導入
2022/7/4 の dependabot のアップデートにより設定ファイル名が以下のように変更され、内容の記述方法も変更されたようです。本記事では最新の記述方法に則って設定ファイルを記述しました。
旧: .dependabot/config.yml
新: .github/dependabot.yml
私の場合、上述した GitHub Actions と同じ理由によりワーキングディレクトリ名を変更しています。
version: 2
updates:
- package-ecosystem: "bundler"
+ directory: "/awesome_events"
schedule:
interval: "weekly"
allow:
- dependency-type: "all"
versioning-strategy: "auto"
この設定ファイルをリポジトリへプッシュすると、dependabot の設定が完了する。設定後は、bundle update
された gem の PR が自動作成される。これを確認してマージすることで更新作業を行うことができる。
$ ruby -v
ruby 2.7.8p225 (2023-03-30 revision 1f4d455848) [x86_64-darwin23]
$ rails -v
Rails 6.0.6.1
上記の私の環境では dependabot のアクション実行時にBundler::SolveFailure with message: Could not find compatible versions
が発生しました。versioning-strategy
やignore
の設定を変更することで対応を試みましたが、every version of bundler depends on Ruby >= 3.1.0
というエラーメッセージから yml ファイル内の設定では解決できない根本的な互換性の問題があるようです。
解決のためには Ruby 3.1.0 以上へのアップグレードが必要なようなのですが、アプリケーションの他の部位への影響が出る可能性を考慮し、今回はこのエラーの解決は断念しました。
Rails での rubocop の使い方
Rails への導入
以下の gem をdevelopment環境へだけ追加
group :development do
gem 'rubocop', require: false
# 以下は元々上記に組み込まれていたが現在は拡張gem扱い
gem 'rubocop-performance', require: false
gem 'rubocop-rails', require: false
end
設定ファイルへ拡張 gem を読み込む設定を追加する
# 拡張gemの読み込み
require:
- rubocop-performance
- rubocop-rails
bundle install
するとbundle exec rubocop
で静的解析実行可能になる
Git のコミット前フックで rubocop を実行
Git の pre-commit フックを使うと、コミット前に Rubocop の検査を実施できる。
Git のフック機能で実行するスクリプトファイルは.git/hooks
ディレクトリ配下へ置き、コミット前フックを実行するにはpre-commit
というファイルを作成する。
以下は、下記の要件を追加したスクリプトの例
- ステージングされたファイルのみを対象とする
- 特定のディレクトリ内(
/awesome_events
)でのみ実行する
#!/bin/bash
# ステージングされているRubyファイルを取得
files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.rb$')
if [ -n "$files" ]; then
# awesome_events内のファイルのみを対象とする場合の処理
awesome_files=$(echo "$files" | grep "^awesome_events/")
if [ -n "$awesome_files" ]; then
# awesome_events内のパスに変換してrubocopを実行
(cd awesome_events && bundle exec rubocop $(echo "$awesome_files" | sed 's|^awesome_events/||'))
fi
fi
一部の cop のみを有効化
チーム方針などで rubocop の一部の検査機能のみを有効にしたい場合はrubocop.yml
に設定を追加する。以下は Lint 種別と Security 種別のみを有効化する例。
require:
- rubocop-performance
- rubocop-rails
+AllCops:
+ DisableByDefault: true
+
+Lint:
+ Enabled: true
+
+Security:
+ Enabled: true
特定の部分のみ rubocop を無効化
rboocop の検査を無効化したい場合は、以下のrubocop:disable cop名
コメントを該当行に追加する。
# if文のガード節チェックを無効化する例
if params[:email].present? # rubocop:disable Style/GuardClause
--auto-gen-config による段階的な rubocop の導入
rubocop 導入の際にデフォルトでは検出項目の量が多すぎる場合は、--auto-gen-config
オプションで初期段階では全てのチェックを無効化した上で段階的に検査項目を増やしながら導入することができる。
以下のオプションコマンドで rubocop を実行すると.rubocop_todo.yml
が生成され、rubocop.yml
には自動で設定が追加される。
% bundle exec rubocop --auto-gen-config
# 上記コマンドで自動で追加される
inherit_from: .rubocop_todo.yml
.rubocop_todo.yml
には rubocop で検出された項目についてそれぞれを抑制・無効化する設定が記述されている。
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2025-02-09 01:03:40 UTC using RuboCop version 1.71.2.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 2
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation, Include.
# Include: **/*.gemfile, **/Gemfile, **/gems.rb
Bundler/OrderedGems:
Exclude:
- 'Gemfile'
.rubocop_todo.yml
を読んで、抑制したままにしておきたい項目の場合は.rubocop_todo.yml
から該当項目を削除し、.rubocop.yml
に以下のように検査を抑制する項目を追加する。
# .rubocop.yml
inherit_from: .rubocop_todo.yml
# ここに永続的な除外設定を書く
Style/Documentation:
Enabled: false
コードを修正すべき項目はそのまま.rubocop_todo.yml
へ置いておく。そして、1つずつ項目を確認してコード修正が完了したら.rubocop_todo.yml
を削除する。
上記までの繰り返しで全ての.rubocop_todo.yml
内の設定項目が削除されれば、必要な項目のみが有効化された状態で設定が完了されたこととなる。
この状態となったら.rubocop_todo.yml
を削除し、.rubocop.yml
内のinherit_from: .rubocop_todo.yml
も削除する。
Brakemanで脆弱性を静的解析
brakeman
gemでRailsアプリケーションの脆弱性を静的解析できる。
導入するには、developmennt環境にgemを追加してbundle install
group :development do
gem 'brakeman' # セキュリティチェック用のライブラリ
end
以下のコマンドで実行すると結果のレポートが出力される。オプションコマンドは以下
-
-A
: デフォルトで検査項目として設定されていない項目も含めて全てを検査する -
-wl
: 検出レベルを軽微なものまで含めたものとする
% bundle exec brakeman
略
== Warnings ==
Confidence: High
Category: Unmaintained Dependency
Check: EOLRuby
Message: Support for Ruby 2.7.8 ended on 2023-03-31
File: .ruby-version
Line: 1
SimpleCovでテストカバレッジを測定する
simplecov
gemを導入するとテスト実行時にテストカバレッジ測定結果をHTMLとして出力できる。
導入は以下のようにする。
1. gemを追加してbundle install
test環境へ追加する。
group :test do
gem 'simplecov', require: false # テストカバレッジ計測用のライブラリ
end
2. 設定ファイルを編集
minitestであればtest/test_helper.rb
、rspecであればtest/spec_helper.rb
へ下記の必要設定を他のコードをrequireする前に追記する。また、カバレッジ測定時は並列テストの設定はオフにする。
ENV['RAILS_ENV'] ||= 'test'
+ require 'simplecov'
+ SimpleCov.start 'rails'
require_relative '../config/environment'
略
class ActiveSupport::TestCase
- # 並列テストの設定はオフにする
- # parallelize(workers: :number_of_processors)
略
end
3. テスト実行
上記設定後にテストを実行するとcoverage/index.html
へカバレッジ測定結果がHTMLで出力される。
Coverallでテストカバレッジを測定する
Coverall
はGitHubと連携してCIで実施したテストのカバレッジをWebページへ表示してくれるサービス。
導入は以下のようにする。
1. gemを追加してbundle install
test環境へ追加する。
group :test do
gem 'coveralls', require: false # テストカバレッジをCoverallsに送信するライブラリ
end
2. 設定ファイルを編集
minitestであればtest/test_helper.rb
、rspecであればtest/spec_helper.rb
へ下記の必要設定を他のコードをrequireする前に追記する。なお、並列テストについては有効化する設定方法も存在するが、必要がない場合はオフにする。
ENV['RAILS_ENV'] ||= 'test'
+ require 'coveralls'
+ Coveralls.wear!('rails')
end
3. テスト実行コードを編集
CI上でテストを実行するコードにCoverall
でリポジトリごとに発行されるトークンを設定する。
COVERALLS_REPO_TOKEN=xxxxxxxxx bin/rails test
上記設定でCI実行時にCoverallsでカバレッジが表示されるようになる。
Skylightで本番環境でのパフォーマンスを測定する
Skylight
は本番環境におけるアプリケーションのレスポンスタイムを測定できるwebサービス。
導入は以下のようにする。
1. Skylightにサインアップ
Skyligtへアクセスし、GETTING STARTED
からサインアップしてセットアップトークンを入手する。
2. gemを追加してbundle install
gem 'skylight'
3. 設定ファイルを作成
入手したトークンを含めて下記コマンドを実行するとconfig/skylight.yml
が自動生成される。このファイルの中にauthentication token
が保存されている。
% bundle exec skylight setup xxxxxxxxx
---
# The authentication token for the application.
authentication: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
4. 本番環境に設定してデプロイ
上記設定で生成したauthentication token
をcredentials
を使って保存するか、サービス運用環境の環境変数SKYLIGHT_AUTHENTICATION_TOKEN
へ保存してデプロイする。
この状態でアプリケーションを運用するとSkylight
のダッシュボードに測定レポートが表示される。
rack-mini-profilerで開発環境でのパフォーマンスを測定する
rack-mini-profiler
gemを導入することでローカルで手軽にRailsアプリケーションのパフォーマンスを測定できる。
導入は以下のようにする。
1. gemを追加してbundle install
develop環境へgemを追加する。
group :development do
gem 'rack-mini-profiler', require: false # パフォーマンス計測用のライブラリ
end
2. 設定ファイルを作成
下記コマンドで必要なファイルが作成される。
% bin/rails g rack_profiler:install
3. ローカル環境でサーバ起動
上記設定を行ってからrails s
でサーバを起動するとページの左上にプロファイルが表示されパフォーマンス測定結果を確認できる。