この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
Ruby on Railsの開発においてsettingslogicを使うと、develop・production・testと環境ごとに異なる環境変数を定義するのに便利であるのと、rspecにてエラー時のテストを実行するのに便利だったので、紹介したいと思います。
settingslogicの使い方とサンプルソース
サンプルソースについて
まず、サンプルとして作成したアプリの動きについて説明します。リクエストを受け付けると、ローカルにあるファイルを読み込み、内容をjson形式で返却するAPIです。読み込むファイルの名称と、格納先フォルダを、settingslogicを利用して定義します。
インストールと定義の作成
1.インストール
Gemfileに以下を記述して、bundle install します。
gem 'settingslogic'
2.定義ファイルの作成
任意のファイル名の定義ファイルを用意し、環境ごとに異なる変数を定義します。今回は「application.yml」というファイル名で、configフォルダ内に配置しました。
defaults: &defaults
file:
folder: <%= Rails.root %>/lib/files
name: default.txt
development:
<<: *defaults
test:
<<: *defaults
file:
folder: <%= Rails.root %>/spec/files
name: test.txt
production:
<<: *defaults
file:
folder: <%= Rails.root %>/lib/files
name: production.txt
yml形式なので、直感的に分かると思います。一番上で全環境共通のデフォルトの定義を行い、その下に環境毎の定義で継承しています。デフォルトと異なる定義については、環境毎の定義にてオーバーライドしています。今回は「file」という項目内にネストして「folder」「name」を定義しています。注意点としては、オーラーライドする場合には「folder」「name」の両方を記述する必要がある点です(片方だけ定義し直そうとしたら読み込まれなかった)。例えば「production:」では、「folder」の定義値はデフォルトと同じですが、重複する形で記述しています。
3.アプリケーションへの設定
上記で用意した定義ファイルをアプリで読み込むため、config\initializers内に「settings.rb」を作成し、以下のように記述します。
class Settings < Settingslogic
source "#{Rails.root}/config/application.yml"
namespace Rails.env
end
[/ruby]
<h3>サンプルソースと動作確認</h3>
<p>
上記で作成した環境毎の定義を使用するサンプルです。
</p>
<h4>1.コントローラ</h4>
<p>
定義ファイルに記述したファイルを読み込み、json形式で返却するためのコントローラです。処理に失敗した場合、HTTPステータスとして500を返却します。
</p>
<h5>files_controller.rb</h5>
class FilesController < ApplicationController
def read
folder = Settings.file.folder
filename = Settings.file.name
@content = File.open(File.join(folder, filename)).read
rescue => e
render :status => 500
end
end
2.JSON
JBuilderを使用してjsonを返却するため、jsonのフォーマットファイルをap/views/files内に作成します。
read.json.jbuilder
json.content @content
3.読み込むファイル
上記の定義ファイル内に記述した、アプリが読み込むファイルを用意します。上記に書いたように、develop・test・productionの各環境毎に異なるファイルを用意します。
lib\files\default.txt
This is a default.
lib\files\production.txt
This is a production.
spec\files\test.txt
This is a test.
4.RSpec
上記で作成したControllerなどをテストするrspecは以下のようになります。
spec\controllers\files_controller_spec.rb
require 'rails_helper'
RSpec.describe FilesController, :type => :controller do
describe "GET 'read'" do
it "returns http success" do
get 'read', { :format => 'json' }
expect(response).to be_success
expect(response.status).to eq(200)
json = JSON.parse(response.body)
expect(json['content']).to eq('This is a test.')
end
it "file not found." do
allow(Settings.file).to receive(:name) { 'error.txt' }
get 'read', { :format => 'json' }
expect(response.status).to eq(500)
end
end
end
6~14行目は正常系のテストで、ファイルを読み込み、内容が返却されてくることをテストしています。返却される値は「3.読み込むファイル」で定義したtest環境用のファイルの内容です。
16~22行目がエラーの場合のテストです。17行目で、mockを使ってsettingslogicで定義した値を一時的に変更し、存在しないファイル名を指定しています。これでエラーが発生することが期待できます。20行目で、エラー時にはHTTPステータスとして500が返ってくることを確認します。
このRSpecを実行すると以下のように表示され、エラーのケースも含めて無事に実行できることが確認できました。(Pendingはありますが)
$ spring rspec spec/
(中略)
4 examples, 0 failures, 2 pending
develop・productionの動作確認
最後に、development・production環境で正しく動くかを確認してみます。まずはdevelopmentからです。コンソールよりRailsを起動し、curlを使い確認します。
rails s
$ curl -X GET http://localhost:3000/files/read
{"content":"This is a default."}
「3.読み込むファイル」で定義したdevelopment環境用のファイルの中身が返却されました。次にproduction環境の確認です。
rails s -e production
$ curl -X GET http://localhost:3000/files/read
{"content":"This is a production."}
こちらもproduction環境用のファイルの中身が返却されました。
まとめ
settingslogicを使うと、環境毎の定義が簡単にできることや、その値をmockで書き換えることでエラー時のテストが可能であることが伝われば幸いです。