undefined method `render_partial_with_logging'というエラーが時々出る。調べてみるとkaminariのthreadsafe系のissueが上がってた。ちょうどrails4アプリのweb serverをpumaにした所だったのでまさにコレっぽい。(heroku + rails4のアプリをpumaにしたらかなり速くなった)

undefined method `render_partial_with_logging' for class `#<Class:0x617ead84>' org/jruby/RubyModule.java:2256:in `alias_method' · Issue #214 · amatsuda/kaminari

上記のissueが修正されたのが4 months ago、kaminari最新の0.14.1がリリースされたのが去年。masterを指定するのは怖いので最後のcommitのrefを指定してアップ。

# Gemfile:
gem 'kaminari',
  git: 'git://github.com/amatsuda/kaminari.git',
  ref: '2ed8adfe378594ae1585ac4a457a6d01f04478eb'

railsでscopeを色々チェインする時にそういや二回joinしたらどうなるんだろうと思ってやってみた。(rails4)

>> User.joins(:events).to_sql
=> "SELECT \"users\".* FROM \"users\" INNER JOIN \"events\" ON \"events\".\"user_id\" = \"users\".\"id\""
>> User.joins(:events).joins(:events).to_sql
=> "SELECT \"users\".* FROM \"users\" INNER JOIN \"events\" ON \"events\".\"user_id\" = \"users\".\"id\""

ホッ、変わらないみたい。

herokuでsmtpを使うためにsendgrid addonを入れる。(smtpにgmailを使う場合は要らない)

$ heroku addons:add sendgrid:starter
# config/environment.rb:

(snip)

ActionMailer::Base.smtp_settings = {
  :address        => 'smtp.sendgrid.net',
  :port           => '587',                                                                                            
  :authentication => :plain,
  :user_name      => ENV['SENDGRID_USERNAME'],                                                                         
  :password       => ENV['SENDGRID_PASSWORD'],                                                                         
  :domain         => 'heroku.com',
  :enable_starttls_auto => true
}
# config/initializers/exception_notification.rb:
AppName::Application.config.middleware.use ExceptionNotification::Rack,
  :email => {
    :email_prefix => "[AppName] ",
    :sender_address => %{"notifier" <notifier@example.com>},
    :exception_recipients => %w{komagata@example.com}
  }
# Gemfile:
gem 'exception_notification'
# config/environments/production.rb:

(snip)

  # config.action_mailer.raise_delivery_errors = false
  config.action_mailer.raise_delivery_errors = true

(snip)

  config.action_mailer.perform_deliveries = true
end
$ gem install icalendar
requre 'icalendar'

calendar = Icalendar::Calendar.new                                                                                 
event = Icalendar::Event.new                                                                                       
event.start = Date.new(2013, 7, 1)
event.end = Date.new(2013, 7, 8)
event.summary = "Foo Festival"
event.description = "Greatest event in the world."
event.location = "Hatsudai Tokyo Japan"
calendar.add_event(event)

puts calendar.to_ical

railsでリンクをクリックしたらiCalファイルダウンロード → iCal起動+登録ってやりたい場合。

class FooController < ApplicationController
  def calendar
    calendar = Icalendar::Calendar.new

    # implementation...

    headers['Content-Type'] = 'text/calendar; charset=UTF-8'
    render :inline, layout: false, text: calendar.to_ical
  end
end
$ heroku labs:enable user-env-compile

これすると行ける。理由はわからん・・・。

jenkins, rspec-railsの場合。

# Gemfile:
group :test do
  gem 'ci_reporter'
end

Rakefileの最終行に下記を追加する。

# Rakefile:
require 'ci/reporter/rake/rspec'

rake specの代わりにrake ci:setup:rspec specを実行するとspec/reports/以下にテスト結果のxmlができるので.gitignoreに追加しとく。

spec/reports/

jenkinsの設定

Build時にrake ci:setup:rspec specでxmlが出力されるようにしておく。怖話ではこんな感じ。

bundle install --binstubs
cp config/database.example.yml config/database.yml
rake db:migrate
rake ci:setup:rspec spec

Post-build Actions > Publish JUnit test result reportを追加し、spec/reports/*.xmlを入力。JUnitがこういうxml出すみたい。

下記のようなグラフが出るようになる。怖話ではこんな感じ。

画像を直リンできるので目につきやすいところに貼るのがいいかも。

東アジアの文字幅を取るeastasianwidthを以前npmに上げましたが、やっぱり怖話で使えそうなので文字列の幅を数字で取るメソッドを追加しました。(半角は1、全角は2みたいに)

javascriptで東アジアの文字幅を取得する - komagata

Ambiguous(曖昧)も含めて東アジアの文字列を考慮した感じで取ります。色んな環境で画面が崩れるようなのでもちゃんと取れるはず。

なんでこんなのが必要なのかというと、要は文字の折り返しを自前で実装するときに、monospaceのフォントで全角分幅を取るのか、半角分幅を取るのかを厳密にわかる必要があるからです。

komagata/eastasianwidth · GitHub

npmで作りましたが結局railsで使うのでgemも作りました。

komagata/eastasianwidth-rails · GitHub

スマホのonclick遅い問題(代わりにtouchstart使う)用のライブラリ、fastclickが定番っぽいので勝手にfastclick-rails作っときました。デフォルトでこうなってほしい。

komagata/fastclick-rails · GitHub

使い方

# Gemfile:
gem 'fastclick-rails'
// app/assets/javascripts/application.js
// require fastclick
# app/assets/javascripts/foo.js.coffee
$ ->
  new FastClick(document.body)

これでスマホの時は勝手にtouchstartになってくれます。300ms違うから体感的にもかなり違う。

HerokuのようにSendGridアドオンを使う。

アドオン画面からSendGridを選び、対象のアプリ/environmentを選んでactivateしておく。

Set it upの内容にしたがってey_configというgemを入れておく。これはEYCと連携した各種サービスのIDとかパスワードとかを良いように扱ってくれる。

メールはsendmailでサラッと送りたい気がするが、EC2上のIPはブロックされてたりするのでSendGridやGmailやSESを使うのが無難なようだ。SendGridは無料プランでは1日200通までなので若干不安ではある。

Set it upに書いてあるようにconfig/environments/production.rbに下記を追加する。

config.action_mailer.delivery_method = :smtp
config.action_mailer.default_charset = "utf-8" # NOT FOUND ON RAILS3.1
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.smtp_settings = {
     :authentication => :plain,
     :address => "smtp.sendgrid.net",
     :port => 587,
     :domain => "yourdomain.com",
     :user_name => EY::Config.get(:sendgrid, 'SENDGRID_USERNAME'),
     :password => EY::Config.get(:sendgrid, 'SENDGRID_PASSWORD')
}

EY::Config.getという部分でサーバー上に良い感じに置かれた設定ファイル(実際には/data/app_name/shared/config/ey_services_config_deploy.yml)から値を読みこんでくれる。

ここで罠なのが、config.action_mailer.default_charsetというメソッドはrails3.1以降は存在しないというところだ。うっかりproductionへデプロイするとサイトがエラーになる。stagingというenvironmentを同じ構成で用意し、試しにデプロイしてみてからの方が無難だろう。

弊社(FJORD, LLC)がEngine Yardとパートナーシップ(的なもの)を結んで怖話Engine Yard Cloud(以後EYC)に移行しました。

(飽くまで”的なもの”で、ちゃんとしたパートナーシップはこういうの

トライアルで検討する

トライアルで試した件については以前こちらに書きました。

Engine Yard Cloudを試す - komagata

本契約前に

貧乏会社なので複数台サーバーなんていくら掛かるのか怖い。料金シュミレーターで予め見積もっときました。

さくらVPSから移行したのは複数台構成のためなので、ちょっと奮発してappサーバー2台+dbサーバー1台の構成にしてみました。高けー!

デプロイ

手順はトライアルの時と同じです。ただ、本契約の場合は東京リージョンが選べます。

アクセスしてみる

appサーバー2台あるけど、どのIPにアクセスしたらいいの?と思いましたが、Application Masterの方のSSHのリンクをクリックする時に出るURLにIPがハイフン区切りで出てるのでそこにアクセスします。(この場合は54.249.225.67)

dbの方もそれで直接dbのインスタンスにsshできます。ユーザー名はdeployでした。

アプリをEYCに合わせる

EYCに載せるに当ってアプリを修正しないといけない点が2点ありました。

rubyを1.9.3系にする

EYCはまだruby2.0.0に対応してないので1.9.3系に変更しました。あんまり変わらないだろうと思ってましたが、encodingのmagic commentが無くていくつかエラーが。泣く泣く追加しました。

ユーザーのアップロード画像をS3に移行

これはEYCだからではなく、appサーバーが複数台になるのでユーザーがアップする画像をローカルに保存してたら迷子になります。幸いpaperclipの画像保存先をS3にするのは簡単で1日あれば対応できました。

データベースの移行

$ ssh bodom "mysqldump -udeployer -pXXXXXXX kowabana_production" | ssh db.kowabana.jp "mysql -uroot kowabana" 

これはコマンド1行でOK。sshで入れるとこういうところが楽ですね。EYCのdb名はアプリ名と同じになるようです。mysqldumpは全テーブルロックするのでデータ量の大きなサイトではこういう雑な移行はオススメできません・・・。

railsアプリのdatabase.ymlの接続先は変えなきゃいけないんじゃないの?と思いましたが、EYCのdeployのレシピで良い感じにdatabase.ymlを生成してくれるそうです。便利。

サポートチャット

トライアルの時もお世話になったサポートチャットですが、グローバルの方は平日の8AM PST - 6PM PST(日本では1時から13時)がサポート時間です。

これは豆ですが、Engine Yardの日本法人のトップページのチャットから発信すれば日本人が日本時間で対応してくれます。

感想

まだ移行したばっかりなのでどうなるかわかりませんが、移行作業自体は思ったより早く簡単にできたなと思います。最近セキュリティ周りがキナ臭いのでその辺は安心感がありますね。(最近別の仕事でウィルスに感染したPHPのサイトの調査をやったばかりです。)

オープンネットワークラボにGithubのPJらが来た時のイベントで「初期のGithubはEngine Yardにサーバーを借りていた」という話を聞いてその後の懇親会でいきなり不躾にも「弊社にもサーバー貸してください!」と@yandoさんに無茶振りしたことから始まった話でしたが色々お手数をお掛けしつつ移行できてよかったです。ありがとうございます。