一分一秒真剣勝負!

Ruby, Railsなど。Web系の技術ネタを充実させたい・・が、そうなるかは分からない。

Ginza.rb 第67回 そろそろAction TextとAction Mailboxをみておこう

ginzarb.doorkeeper.jp

資料: https://gist.github.com/y-yagi/25171f5b6bb24d320ee69517fa7fdebf

遅い投稿。Ginza.rb 第67回目に参加しました。 Action Text / Action Mailbox どちらも使うかは微妙だなという感覚だったけど、これらの実装が Active Storage に依存している事が分かり、Active Storage はこの為にリリースされたんだなあってことが分かったのが素敵でした。なんで今さらファイルアップローダーなんかRailsに入れるんだよという謎が溶けた瞬間だった。 しかし今後、Action Text / Action Mailbox どちらかを使うなら、問題が起きた時など Active Storage の実装も追う事になると分かったのでぐぬぬ・・といったところ。

あと思ったのは勉強会の感想の記事は参加後のなるべく早い段階で書いたほうがいいな〜ってこと。なんかあと2〜3ぐらいいいこと思いついた記憶があるんですよ。なんだっけな〜。

Elasticsearch2.3.3から5.4.3への移行作業

去年からElasticsearchをいじってたんだけど、全くブログなどに書いてなかったので書いてみる。 ツッコミとか大歓迎です。

あらすじ

HerokuのAdd-onsでElastic Cloudを使っているのですが、ある日、Elasticsearch 2.3 のサポート期限終了のお知らせが届きました。

Elasticsearch 2.3 reaches end of life (EOL) on September 30

This is a friendly reminder that Elasticsearch 2.3 reaches end of life on September 30, 2017. According to our records, you are still running one or more Elastic Cloud clusters using Elasticsearch version 2.3. Before that date, you need to upgrade your clusters to a more recent version. We highly recommend you to upgrade to the latest version which is Elasticsearch 5.4. Please note that if you upgrade from an Elasticsearch version prior to version 5 make sure you read the documentation on how to Upgrade to Elasticsearch 5.x.

If you have not upgraded your clusters by September 30, we will upgrade the clusters to the latest available version on the 2.x branch for you. As of today, this is Elasticsearch 2.4.

If you have a Cloud Gold or Platinum subscription, our support engineers can help you with this upgrade. Open a case to get started.

Kind Regards,

Your Elastic Cloud Team

サポートの終了がちょっと早い気もしたけど、古いバージョンをいつまでもサポートするのは良くない文明派なので素直にバージョンアップすることにしました。

状況

  • Heroku
  • Elasticserch(2.3.3)をHeroku Add-onsから利用中
  • indexの元ネタはPostgresqlから1日1回インポート
  • バージョン5.4.3へダウンタイムゼロで移行したい

バージョンアップ前の確認

Elasticsearch Migration Helperというバージョンアップ前のチェックツールが公式より提供されています。 Elastic Cloudでは標準でこれがインストール済みなので確認します。

f:id:yatmsu:20170716002629p:plain

自分の環境ではオールグリーン。 でも実際は1.xの時に作成した未使用のindexが残っていて、初回はレッドになりました。indexの1.x→5.xへの移行はできないんですね。これは削除するだけの対応で終了となりました。

Blue-Greenデプロイをしたい

Elasticsearchはメジャーバージョンアップを行う場合、Full cluster restart upgradeでバージョンアップを行わなければならない為、一定の時間クラスタが停止してしまいます。 そこで、ダウンタイムゼロでの移行を実現する為Blue-Greenデプロイをしようと考えました。リモートクラスタからもデータ参照が可能になったReindex APIを使えば簡単にできそうだなと予測。 しかし、複数クラスタを起動しようとしたところ、Heroku Add-onsのElastic Cloudだと単一のクラスタしか起動できない(Elastic Cloud単体で契約すると複数クラスタの起動可能)事に気付きました。これではBlue-Greenデプロイ出来ない。

別のappを使ってBlue-Greenデプロイ

そこで、ステージング環境として使っていたappで起動しているElasticsearchのクラスタを5.4.3に移行し、一時的にプロダクションからステージングのElasticsearchを参照させ、その間にプロダクションのバージョンを上げ、Elasticsearchの向き先を戻す・・・という手順で移行しました。

Elasticsearch(production-app)

     ↑ 通常はこっちを参照

WebServer(production-app)

     ↓ 一時的にこちらを参照させる

Elasticsearch(staging-app)

なんかイマイチだけど、まあこんなもんですね。

こうしておけば良かったこと

HerokuのAdd-onsではなく、Elastic Cloud単体で契約しておけばよかったなと。 Elastic Cloudは素晴らしいサービスなんだけども、HerokuのAdd-onsだと複数クラスタの運用が出来ないことだけが残念でした。今後の複数クラスタ起動対応に期待。

Railsの開発用サーバをPowからPuma-devへ乗り換えた

Rails5からデフォルトRackサーバがPumaになりました。開発用のサーバとして自分はずっとPowを使っていましたが、Pumaを使っているのであればPowではなくpuma-devが主流になっていると知って調べてみたところ、PowからPuma-devへの乗り換えを即決しました。 個人的にいいなと思ったのは以下の点。

  • Pow同様「zero-config Rack server」である
  • Websocketsをサポート
  • Linux対応(全機能を使うには追加のインストールが必要)
  • 開発が活発(Powは実質開発が止まっている)
  • powder相当のコマンドがPuma-devにはデフォルトで組み込まれている(puma-dev link)

Macでのインストール手順は以下のとおり。

$ curl get.pow.cx/uninstall.sh | sh # Powのuninstall
$ brew install puma/puma/puma-dev
$ sudo puma-dev -setup
$ puma-dev -install

これだけ。使い方は基本的にPowを踏襲していて、移行はスムーズにいけます。

$ cd /path/to/my/app; puma-dev link -n appname  #  Rackアプリを登録(~/.puma-devへシンボリックリンクを貼る)
+ App ‘appname' created, linked to '/Users/hoge/.puma-dev/appname'

http://appname.dev or https://appname.dev へアクセスできるようになります。 サーバの再起動もPowのままで、tmp/restart.txtをtouchするだけ。 また、puma-devにシグナルを送れば全アプリを一気に再起動できる。

$ touch tmp/restart.txt # サーバ再起動(Rackアプリの直下で実行)
$ pkill -USR1 puma-dev # 全アプリを再起動

しかしPowもそうだったけど「zero-config」で快適に使えるソフトって素晴らしいですね。 例えばfish shellもデフォルトの設定でかなり使えるという触れ込みなので、zshから移行しようかなと思ってたりします。

github.com

ActiveRecordで引数があるscopeはクラスメソッドで定義しろ!

タイトルの通りActiveRecordでscopeを使う場合、引数が必要であればクラスメソッドを使うことがRails Guideで推奨されている。 これを知ったのはかなり前のことで、その時から自分は引数を受け取るscopeをクラスメソッドとして定義しています。

class Article < ActiveRecord::Base
  def self.created_before(time)
    where("created_at < ?", time)
  end
end

Using a class method is the preferred way to accept arguments for scopes. These methods will still be accessible on the association objects:

category.articles.created_before(time)

Active Record Query Interface — Ruby on Rails Guides

推奨されているだけであって、別にscopeを使いたければ使ってもいいのだけど、今となってはnamed_scopeを使えば遅延評価が便利〜。とかクラスメソッドでも同じような(厳密には違うけど)ものだし、自分の場合scopeで定義するのは

# 編集可能な記事
scope :editable, -> { where(state: 'editable') }

のように、アプリの多くの場所から呼びされシンプルな絞り込みの条件だけで使うようにしています。

Rails俺は気づかなかったシリーズ「改行コードをHTMLタグに置換」

文字列の改行コードを
タグに置換したい!とかよくある事だったので、毎回helperに#brとかメソッドを定義していたけど、simple_formatというヘルパが既に定義されていた。

my_text = "Here is some basic text...\n...with a line break."

simple_format(my_text)
# => "<p>Here is some basic text...\n<br />...with a line break.</p>"

simple_format(my_text, {}, wrapper_tag: "div")
# => "<div>Here is some basic text...\n<br />...with a line break.</div>"

more_text = "We want to put a paragraph...\n\n...right there."

simple_format(more_text)
# => "<p>We want to put a paragraph...</p>\n\n<p>...right there.</p>"

simple_format("Look ma! A class!", class: 'description')
# => "<p class='description'>Look ma! A class!</p>"

simple_format("<blink>Unblinkable.</blink>")
# => "<p>Unblinkable.</p>"

simple_format("<blink>Blinkable!</blink> It's true.", {}, sanitize: false)
# => "<p><blink>Blinkable!</blink> It's true.</p>"

全然気づかなかったこれ。Railsが用意してるなら、使っていかないとだな。

RailsでCustom FormBuilderのテストってみんなどう書いているんだろう

RailsでFormBuilderを独自拡張した場合のSpecってあまり言及されていないよなと思う。

例えば、こんな感じで独自FormBuilderを書いたとする。

app/forms/application_form_builder.rb

するとSpecはこんな感じかなあと思っているのだけど・・・。

spec/forms/application_form_builder_spec.rb

なんかしっくりこない。 ActionView::Helpers::FormBuilderのコミットログを見ると、initializeメソッドの引数が変更になることもあるので、form_forを呼んでから書くというのがいいかなとか考えてる。 コードとしてはこんな感じ。 form_forから書いた方がClassを直で呼ぶより保守性が高いかな?

参考URL