Sooey

2016-05-21 23:31:51 +0900

CircleCI上でのRails 5.0.0.rc1 + factorygirlrailsのビルドがPG::UndefinedTableで失敗する件

以下のような構成のRailsアプリをCircleCIでビルドする際、

  • Rails 5.0.0.rc1
  • factory_girl_rails 4.7.0

rake db:create db:schema:loadrake db:create db:structure:loadのフェーズで以下のような例外が発生してビルドが失敗するようになった。

ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  relation "posts" does not exist
LINE 8:                WHERE a.attrelid = '"posts"'::regclass
                                          ^
:               SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                     pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
             (SELECT c.collname FROM pg_collation c, pg_type t
               WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation),
                     col_description(a.attrelid, a.attnum) AS comment
                FROM pg_attribute a LEFT JOIN pg_attrdef d
                  ON a.attrelid = d.adrelid AND a.attnum = d.adnum
               WHERE a.attrelid = '"posts"'::regclass
                 AND a.attnum > 0 AND NOT a.attisdropped
               ORDER BY a.attnum    

スタックトレースやrake db:schema:load fails - CircleCIを見た結果、以下のような流れになっていることがわかった。

  • Railsのロード過程でfactory_girl_rails/railtie.rbが読み込まれる
  • FactoryGirl.find_definitionsが呼び出される
  • spec/factories/*.rbが読み込まれる
  • モデルクラスがロードされる
  • モデルクラスに対応するテーブルがまだ存在しないため例外が発生

Rails 5.0がリリースされるまでの過程で解消するのかもしれないが、ひとまずGemfileではfactory_girl_railsrequireしないようにして、

group :test do
  ...
  gem 'factory_girl_rails', '4.7.0', require: false
  ...
end

そのかわりにspec/spec_helper.rbで明示的にrequireする形にして問題を回避することにした。

#
# factory_girl_rails
#
# To prevent PG::UndefinedTable excetion during `rake db:structure:load` on
# CircleCI build, we don't require the gem in Gemfile.
# Because of this, we need to require it explicitly here.
#
# See: https://circleci.com/docs/ruby-exception-during-schema-load/
#
require "factory_girl_rails"

2016-04-02 17:57:46 +0900

CircleCI上でCapybara, Poltergeist, PhantomJSを利用したテストがMouseEventFailed失敗する問題を解消した。

以下のような構成のRailsアプリをCircleCI上でビルドすると、Capybara::Poltergeist::MouseEventFailedという例外が発生してテストが失敗するケースがあった。

  • Rails 4.2.x
  • RSpec 3.4.x
  • Capybara 2.6.2
  • Poltergeist 1.9.0
  • PhantomJS 2.1.1 (CircleCIのプロジェクト設定でUbuntu 14.04 (Trusty) containerを利用するように設定しておく必要あり)

この時、失敗の原因となっているテストコードは、

click_link '日本語のラベル'

のようなもの。

調査のためにCircleCIにSSHで接続し、テストコードにsave_screenshot('test.png', full: true)を追加&実行して取得した画像ファイルをscpでローカルにダウンロードして確認してみたところ、日本語フォントが無い状態でページがレンダリングされており「日本語のラベル」に該当する要素がページ上では目視できない状態になっていた。

そこで、cricle.ymlに以下のようなエントリを追加してビルド前に日本語フォントがインストールされるようにすることで、テストが無事に成功するようになった。

dependencies:
  pre:
    - sudo apt-get install fonts-migmix

2016-03-25 14:58:16 +0900

Herokuで運用しているRailsアプリのJS依存管理をBowerからnpmへ移行しました。

これまで、Herokuで運用しているRailsアプリにおいて各種JavaScript/CSSパッケージの依存管理をBower(およびqnyp/heroku-buildpack-ruby-bower)で行ってきましたが、

  • npmによる依存管理でも同じことが実現できるようになった
  • Rails内にES6環境を構築するにあたってnpmを利用する必要がでてきた

という理由から、Bowerではなくnpmを利用する構成に移行しました。

具体的な作業手順は以下のとおりです。

まず、npm initコマンドでRailsプロジェクトのルートディレクトリにpackage.jsonを生成します。

$ npm init

bower.jsonに記載していた依存パッケージのエントリをpackage.jsonに記載します。この際、パッケージ名が変わるものもあるので https://www.npmjs.com/ でnpmにおけるパッケージ名を調べておきます。

依存パッケージをnpmでインストールします。

$ npm install

これによって、Railsプロジェクトのルートディレクトリにnode_modulesディレクトリが作成され、その中にパッケージがインストールされます。node_modules.gitignoreに追加しておき、リポジトリには含まれないようにしておきます。

Railsの設定に以下の記述を追加します。

Rails.application.config.assets.paths << Rails.root.join('node_modules/')

これによって、npmでインストールされたパッケージのファイルをapp/assets/javascripts/application.jsなどから//= requireディレクティブで参照できるようになります。指定する際はnode_modules/からの相対パスを記述します。

Herokuにデプロイする際にnpm installが実行されるようにするために、HerokuアプリのBuildpackとしてheroku/nodejsheroku/rubyを設定します。

$ heroku buildpacks:set heroku/ruby
$ heroku buildpacks:add --index 1 heroku/nodejs

設定した結果、以下のようにheroku/nodejsが先に実行されるようになっている必要があります。

$ heroku buildpacks
=== myapp Buildpack URLs
1. heroku/nodejs
2. heroku/ruby

以上で、Herokuへのデプロイ時にnpmによって依存パッケージがインストールされるようになります。

2015-12-16 00:27:35 +0900

Herokuのアプリケーションログを外部サービスにsyslogで転送するdrainsという仕組みにおいてTLS syslogが正式にリリースとなったので、ログの保存に利用しているサービス Papertrailとの通信をTLS syslogに変更した。

手順は以下の通り。

  1. Papertrailにログインして、Destination Settingsページで"Accept connections via..."の"TCP: TLS encryption"チェックボックスをチェックする

Screen Shot 2015-11-19 at 18.47.50.png (116.6 kB)

  1. HerokuのdrainsにTLS syslogを追加する

    $ heroku drains:add syslog+tls://logs2.papertrailapp.com:XXXXX Successfully added drain syslog+tls://logs2.papertrailapp.com:XXXXX

    $ heroku drains syslog://logs2.papertrailapp.com:XXXXX syslog+tls://logs2.papertrailapp.com:XXXXX

  2. Herokuのdrainsから古いsyslogを削除する

    $ heroku drains:remove syslog://logs2.papertrailapp.com:XXXXX Successfully removed drain syslog://logs2.papertrailapp.com:XXXXX

    $ heroku drains syslog+tls://logs2.papertrailapp.com:XXXXX

  3. PapertrailのDestination Settingsページで"Accept connections via..."の"TPC: Plain text"チェックボックスを外す

Screen Shot 2015-11-19 at 18.51.45.png (113.4 kB)