背景
Rails Engineを触ってみたのでメモ。
Engineとは何かなどは http://guides.rubyonrails.org/engines.html
サンプル
適当なサンプルということで、発生した例外をDBに保存するような仕組みを考える。
Engineの役目は、エラーの詳細を見るための画面や、例外保存処理をホストアプリに提供することである。
生成
rails plugin new error_catcher -T --dummy-path=spec/dummy --mountable
-T
でtest
関連の生成をスキップ。使い慣れているのがrspecなもので。。。
--dummy-path=spec/dummy
は、engineの動作確認用のdummyのrailsアプリが生成されるパス。rspecを使うので、dummyアプリの置き場所もspec
以下にする。
--mountable
で、独立した名前空間を持ったskeltonが生成される。(正直ここはふわっとした理解)
rspecの準備
以下を追記。
s.test_files = Dir["spec/**/*"]
s.add_development_dependency "rspec-rails"
config.generators do |g|
g.test_framework :rspec
end
helperファイルを生成
bundle install
bin/rails g rspec:install
spec_helper.rbとかrails_helper.rbが生成される。
enviromentの読み込み先をdummyアプリに変える
require File.expand_path('../dummy/config/environment', __FILE__)
モデルを作成
bin/rails g scaffold error name:string description:string stacktrace:text fired_at:datetime
bundle exec rake db:migrate
ダミーアプリを起動
cd spec/dummy
bin/rails s
http://localhost:3000/error_catcher/errors
よくあるIndex画面が出るはず。
specを書いてみる
scaffoldで生成していれば、spec/models/error_cathcer/error_spec.rbが存在するはず。これを以下のように修正してみる。
require 'rails_helper'
describe ErrorCatcher::Error do
describe 'Validation' do
it 'nameは必須' do
error = described_class.new
expect(error.valid?).to be_falsey
end
end
end
実装も直す。
module ErrorCatcher
class Error < ActiveRecord::Base
validates :name, presence: true
end
end
bundle exec rspec spec/models/error_cathcer/error_spec.rb
でテストが通るはず。
ホストアプリ側から呼び出すメソッドを実装する
ホストアプリ側からは、直接Modelを呼ぶのではなく例外保存用のインタフェースを呼ぶ。モデルを直接ホストアプリから呼ぶこともできるが、アプリとgemの依存関係が強くなってしまうので、別途外向けのインタフェースを用意する。
module ErrorCatcher
module Catcher
def catch e
error = ::ErrorCatcher::Error.new
error.name = e.class.name
error.description = e.message
error.stacktrace = e.backtrace.join("\n")
error.fired_at = Time.now
error.save!
end
end
end
アプリへ組み込み
error_catcherを利用する適当なアプリを作る。今回はerror_catcherと同じ階層に作る。
rails g new error_thrower
cd error_thrower
bin/rails g scafold item name:string description:string price:integer
gem 'error_catcher', path: '../error_catcher'
bundle install
error_catcher
が提供するmigrationファイルを取得&migration。
bundle exec rake error_catcher:install:migrations
bundle exec rake db:migrate
コントローラで予期せぬ例外が起きたら全てキャッチして保存する。
include ErrorCatcher::Catcher
rescue_from Exception, with: :error_handler
def error_handler e
catch(e)
render file: "#{Rails.root}/public/500.html", layout: false, status: 500
end
エラーが起きた時の動作確認のために、Validationをかける。
validates :name, presence: true
error_thrower/app/controller/items_controller
内の@item.save
を全て@item.save!
に変えて、画面から空入力で保存するとValidationErrorが起きるようにする。
bin/rails s
http://localhost:3000/items/new から空で保存すると、エラー画面が表示され、http://localhost:3000/error_catcher/errors を見れば発生したエラーが保存されている。
これで、例外保存、閲覧の仕組みをRailsアプリに組み込むEngineができたことになる
作ったものはこちら https://github.com/hokuma/error_catcher