LoginSignup
10
8

More than 5 years have passed since last update.

Rails Engineメモ

Last updated at Posted at 2016-04-10

背景

Rails Engineを触ってみたのでメモ。

Engineとは何かなどは http://guides.rubyonrails.org/engines.html

サンプル

適当なサンプルということで、発生した例外をDBに保存するような仕組みを考える。

Engineの役目は、エラーの詳細を見るための画面や、例外保存処理をホストアプリに提供することである。

生成

rails plugin new error_catcher -T --dummy-path=spec/dummy --mountable

-Ttest関連の生成をスキップ。使い慣れているのがrspecなもので。。。

--dummy-path=spec/dummyは、engineの動作確認用のdummyのrailsアプリが生成されるパス。rspecを使うので、dummyアプリの置き場所もspec以下にする。

--mountableで、独立した名前空間を持ったskeltonが生成される。(正直ここはふわっとした理解)

rspecの準備

以下を追記。

error_catcher.gemspec
s.test_files = Dir["spec/**/*"]
s.add_development_dependency "rspec-rails"
lib/error_cathcer/engine.rb
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アプリに変える

spec/rails_helper.rb
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が存在するはず。これを以下のように修正してみる。

spec/models/error_catcher/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

実装も直す。

app/models/error_catcher/error.rb
module ErrorCatcher
  class Error < ActiveRecord::Base
    validates :name, presence: true
  end
end
bundle exec rspec spec/models/error_cathcer/error_spec.rb

でテストが通るはず。

ホストアプリ側から呼び出すメソッドを実装する

ホストアプリ側からは、直接Modelを呼ぶのではなく例外保存用のインタフェースを呼ぶ。モデルを直接ホストアプリから呼ぶこともできるが、アプリとgemの依存関係が強くなってしまうので、別途外向けのインタフェースを用意する。

lib/error_catcher/catcher.rb
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
Gemfile
gem 'error_catcher', path: '../error_catcher'
bundle install

error_catcherが提供するmigrationファイルを取得&migration。

bundle exec rake error_catcher:install:migrations
bundle exec rake db:migrate

コントローラで予期せぬ例外が起きたら全てキャッチして保存する。

error_thrower/app/controller/application_controller.rb
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をかける。

error_thrower/app/models/item.rb
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

10
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
8