settingslogicを使った環境毎の定義と、rspecでの値の一時的な書き換え
はじめに
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で書き換えることでエラー時のテストが可能であることが伝われば幸いです。