日々雑記

旅行の事ばっかり。神社成分多め。
Recent Tweets @

Ruby on Rails 4.2 Release Notesを読んだのでメモ。とりあえず、Major FeaturesとIncompatibilitiesについて。

Major Features

Active Job, Action Mailer #deliver_later

Active JobはResque, Delayed Job, Sidekiqのようなキューイングシステムのアダプター用フレームワーク。

Active Job APIを使用すると、キューイングシステムに依存しないjobを作成する事が出来ます。

Active Jobが組み込まれた事により、Action Mailerに#deliver_laterというメソッドが追加されています。このメソッドを使用すると、メール送信処理用のjobがキューに追加される(バックエンドでやってくれる)。 因みに、これに伴い、#deliver_nowというメソッドも追加されており、従来の#deliverのように即時にメールを送信したい場合は、こちらを使う必要があります。#deliverは非推奨になり、Rails 5で削除予定との事。

GlobalIDを使うと簡単にActiveRecordオブジェクトをシリアライズしてjobに渡すことができます。 ActiveRecordのシリアライズ/デシリアライズは自動で行われるので、jobには、idではなくActiveRecordのオブジェクトをそのまま渡してあげればOK。

GlobalIDは独自のURIを使って、データを一意に表現しているらしい。フォーマットは以下の通り。

gid://YourApp/Some::Model/id

ActiveRecordはGlobalIDをロードしているので、to_gidメソッドでGlobalIDを取得出来る。

User.first.to_gid.to_s  # => gid://rails420-sample/User/1

他にも、 Signed Global IDs というのもあるらしい。詳細はGlobalIDのREADME参照。

Adequate Record

Adequate RecordはActiveRecordをリファクタリングしたもので、findfind_by、及び幾つかのアソシエーションのqueryが2x高速になっている。

Adequate Recordは、ActiveRecordが呼ばれた際に、SQL queryをキャッシュする事で高速化を行っている。詳細はAaronのブログ参照。

使用する側は、特に何もする必要は無し。殆どのfindfind_byメソッド、アソシエーションのクエリーは自動でキャッシュが利用される。例:

Post.find 1  # caches query pattern
Post.find 2  # uses the cached pattern

Post.find_by_title 'first post'  # caches query pattern
Post.find_by_title 'second post' # uses the cached pattern

post.comments        # caches query pattern
post.comments(true)  # uses cached pattern

以下の場合はキャッシュが使用されない。

  • modelがdefault scopeを持っている場合
  • modelが単一テーブル継承(STI)を使用している場合 
  • findにidのリストを渡した場合。例えば、
Post.find 1  # caches query pattern
Post.find(1,2,3)
OR
Post.find [1,2]
  • find_byを sql fragmentsと一緒に使用した場合
Post.find_by "published_at < ?", 2.weeks.ago

Web Console

Rails 4.2で新規アプリを作成した場合、デフォルトでWeb Consoleのgemが追加されている。

Web Consoleはrails アプリのデバッグ用ツールで、エラーページ上にインタラクティブコンソールを追加してくれます。

エラーページ上のインタラクティブコンソールはexceptionが発生した箇所で自由にコードを実行する事が出来る。エラーの調査に便利。

consoleメソッドを使用すると、任意のviewにインタラクティブコンソールを追加出来る。

Web Consoleを使用すると、ブラウザ上からテストデータの作成・変更を行う事が出来る。

えーっと、用は、better_errorsみたいなもので、better_errorsと違うのは、任意のviewにコンソールを追加出来るのと、特定のURLにマウント出来る点かなあ。

Web Consoleについては、以前別エントリにまとめたので、宜しければこちらもどうぞ。

Foreign key support

migration DSLがforeign keysの追加/削除をサポートするようになった。schema.rbにもちゃんと出力される。今の所、mysqlmysql2postgresqlアダプターだけがforeign keysに対応している。

# add a foreign key to `articles.author_id` referencing `authors.id`
add_foreign_key :articles, :authors

# add a foreign key to `articles.author_id` referencing `users.lng_id`
add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"

# remove the foreign key on `accounts.branch_id`
remove_foreign_key :accounts, :branches

# remove the foreign key on `accounts.owner_id`
remove_foreign_key :accounts, column: :owner_id

詳細はAPI Doc(add_foreign_keyremove_foreign_key参照。

Incompatibilities

以前deprecatedだった機能は全て削除されています。 このリリースで非推奨になったものについては、個々のモジュールのrelease noteを参照して下さい。

以下に、アップデート後直ぐに対応が必要なものについて記載します。

render with a String argument

以前までは、render "foo/barrender file: "foo/bar"と同等だったが、Rails 4.2ではrender template: "foo/bar"になった。もしファイルのレンダーを行いたい場合、render file: "foo/bar"とする必要があります。

respond_with / class-level respond_to

respond_withメソッドと、クラスレベルのrespond_toメソッドはrespondersgemに移動された。以下のようなコードを記載している場合、gem 'responders', '~> 2.0'をgemfileに追加する必要があります。

# app/controllers/users_controller.rb

class UsersController < ApplicationController
  respond_to :html, :json

  def show
    @user = User.find(params[:id])
    respond_with @user
  end
end

Default host for rails server

Rackの変更により、rails serverは0.0.0.0の代わりにlocalhostをリッスンするようになった。

ローカル環境でのみ作業する場合は問題無いが、異なるマシンからRailサーバにアクセスする場合に、問題が起きる可能性があります。0.0.0.0でサーバを起動したい場合、rails server -b 0.0.0.0とすればOK。

Production logging

production環境のデフォルトのログレベルが、:debugになった。元々のログレベルにしたい場合、config/environments/production.rbに 以下設定を行えばOK。

# config/environments/production.rb

# Decrease the log volume.
config.log_level = :info

HTML Sanitizer

HTML sanitizerが新しいライブラリに置き換えられています。

出力内容も変わっており、元々のsaniterが必要な場合、rails-deprecated_sanitizerをGemfileに追加すればOK。自動で以前の振る舞いを行ってくれるとのこと。

rails-deprecated_sanitizerはRails 4.2のみをサポートしており、Rails 5.0が出るまでは保守されるとのこと。

より詳細な変更内容は、こちらのブログ参照。

assert_select

assert_selectはNokogiriベースの処理に変更になっています。

結果、幾つかのセレクタがサポート外になっています。もしそれらのセレクタを使用している場合、更新する必要があります。

  • 属性のvalueに対するセクレクタに非アルファベット文字を含んでいる場合、クォートする必要があります
a[href=/]      =>     a[href="/"]
a[href$=/]     =>     a[href$="/"]
  • 不適切な要素のネストのような、不正なHTMLを含んでいる場合

# content: 
# before: assert_select('div > i') # => true assert_select('div > p') # => false assert_select('i > p') # => true # now: assert_select('div > i') # => true assert_select('div > p') # => true assert_select('i > p') # => false
  • データセレクタにエンティティが含まれている場合、元々はrawデータで比較されていたのが、評価後の値で比較される

とりあえずはここまで。各ライブラリについては、いずれ。

minitest-slow_testというgemを作ったのでご紹介。

内容

またminitestのplugin。ソースはこちら

テスト完了時に、一定以上時間のかかったテストの一覧を表示してくれます。

実行例

$ ./bin/rake test
Run options: --seed 4004

# Running:

........................

Finished in 3.367417s, 7.1271 runs/s, 16.0360 assertions/s.

24 runs, 54 assertions, 0 failures, 0 errors, 0 skips
[SlowTest]PageIntegrationTest#test_create_new_page : 1.17s
[SlowTest]PageTest#test_do_not_find_page_when_use_invalid_title : 1.00s

遅かったテストの、テスト名と実行時間が表示されます。 MySQLのslow queryみたいないめーじ。

specでの表示もOK。

[SlowTest] TodoIntegrationTest::todoの新規作成を行ったとき#test_0001_作成したtodoが表示されること : 1.87s

結果はテスト実行毎ではなくて、最後にまとめて表示。

テスト実行時に処理が遅いテストについてチェックするようにしているのですが、数が多くなると一つ一つチェックするのが面倒で、処理が遅かったテストの一覧だけ見れるようにしたかったので作りました。

テストが遅いって事は、テスト対象の処理が遅い可能性が高いので、チェックするに越した事は無いかなーと。

使い方

Gemfieにgem 'minitest-slow_test'を追加して、bundleを実行して終了。後は普通にテストを実行するだけでOK。

デフォルトでは1秒以上かかるテストを表示するようにしています。この時間を変更したい場合は、Minitest::SlowTest.long_test_timeに値を設定すれば変更可能。

require 'minitest/slow_test'

Minitest::SlowTest.long_test_time = 0.5  # 秒で指定

こんな感じで。

現状、インテグレーションテストとユニットテストで同じ閾値になってしまうので、そこは変えれるようにしたい。JS絡むテストはどうしても遅くなってしまうので…。

Rails 4.2から導入されたweb-consoleについて試してみたのでメモ。なお、試したバージョンは’2.0.0.beta3’。Rails 4.2.beta1だと、2.0.0.beta2がGemfileに記載されているが、2.0.0.beta2はルーティングエラー時にエラーになるバグがあるのでbeta3で。

web-consoleとは

Rails 4.2のMajor Featuresの一つ。

デフォルトエラーページ用のデバッギングツールで、ブラウザ上からインタラクティブにconsoleの操作が出来る。

github上の画像引用


エラーが起きた箇所で操作が出来るだけではなく、traceを選択する事で、選択した箇所での値の確認も出来る。Better Errorsみたいなもん。

consoleは、エラーページだけでなく、任意のviewで表示する事が出来る。表示させるには、表示させたいviewでconsoleメソッドを呼び出すだけでOK。呼び出せるのは、development/test環境のみ。


consoleメソッドで呼び出す以外に、consoleを特定のURLにマウントさせる事も出来る。マウントさせるには、config.web_console.automount = trueを設定してあげればOK。因みに、この設定は将来はデフォルトtrueにするらしい。


デフォルトのマウント先は/console。こちらのパスは config.web_console.default_mount_path で変更可能。

他にも、接続元IPを制限したら、timeoutの設定等を行う事が出来る。詳細はconfiguration参照。

style

consoleは、スタイルの設定も行う事が出来る。設定出来るのは、colorとfont。

カラーテーマには以下のようなものがある。

  • monokai: the default Sublime Text colors
  • solarized_dark: light version of the common solarized colors
  • solarized_light: dark version of the common solarized colors
  • tango: theme based on the tango colors
  • xterm: the standard xterm theme

monokaiを設定するとこんな感じ。


カラーテーマは自分で定義する事も出来る。

  WebConsole::Colors.register_theme(:custom) do |c|
    # The most common color themes are the 16 colors one. They are built from 3
    # parts.

    # 8 darker colors.
    c.add '#000000'
    c.add '#cd0000'
    c.add '#00cd00'
    c.add '#cdcd00'
    c.add '#0000ee'
    c.add '#cd00cd'
    c.add '#00cdcd'
    c.add '#e5e5e5'

    # 8 lighter colors.
    c.add '#7f7f7f'
    c.add '#ff0000'
    c.add '#00ff00'
    c.add '#ffff00'
    c.add '#5c5cff'
    c.add '#ff00ff'
    c.add '#00ffff'
    c.add '#ffffff'

    # Background and foreground colors.
    c.background '#ffffff'
    c.foreground '#000000'
  end

  # Now you have to tell Web Console to actually use it.
  config.web_console.style.colors = :custom

fontはconfig.web_console.style.fontに値を設定する事で変更可能。デフォルトは、large DejaVu Sans Mono, Liberation Mono, monospace

まとめ

better_errorsを使っているので、無理に使わなくて良いかなーと思っていたのだが、マウントさせて使うのが割と便利だった。

ローカルの開発環境以外の環境(デザイナーさんや、コーダーさんの環境等)のデータをちょっと操作したい、という場合には重宝しそうなので、そういうケースが多い人には、割とおすすめかと。

大分久し振りの一宮巡り。東北編 Part3。 春に行った新潟の記事を書くのを忘れていた…。後でまとめて書くか。

鳥海山大物忌神社 吹浦口ノ宮

出羽国一宮、鳥海山大物忌神社。 まずは、吹浦口。

鳥海山大物忌神社は、名前の通りご神体は鳥海山にあり、本社は鳥海山山頂にある。ふもとには「口ノ宮」と呼ばれる里宮が吹浦(ふくら)と蕨岡(わらびおか)の二箇所に。

吹浦も蕨岡も鳥海山の登山口で、昔は他にも登山口があり、どこが一宮を名乗るかは結構揉めたらしい。詳細はwikiご参考

色々とあった結果、明治4年に、山頂を一宮、吹浦と蕨岡口ノ宮とする事で落ちついたとの事。一応三社併せた総称として「鳥海山大物忌神社」となっている。その後、改めて吹浦を口之宮と定めて社務所を置き、蕨岡は摂社として遇されて今に至っているとの事。

なので、宮司さんは吹浦に常駐しているので、御朱印が欲しいならとりあえず吹浦に来るのが良いかと。蕨岡にもいらっしゃる事あるらしいのだが、今回は会えなかった。

創祀は564年で、祭神は大物忌神(おおものいみのかみ)。由緒によると、倉稲魂命・豊受姫神と同神との事。記紀に存在しない神様なので、後付けで同神になったのかなあ。鳥海山噴火が兵乱の前兆であると信じられていた節があり、守り神的な位置づけでもあったらしい。

で、社内。

吹浦は月山命が合わせて祀られており、本殿が2つ。これについて詳細な説明が見つからなかったんだが、単純に月山が近いからかなあ。

決して大きい神社ではないのだが、拝殿も本殿も趣が感じられて非常に良かった。あと駅近。助かる。

祭神:大物忌神(おおものいみのかみ)、倉稲魂命・豊受姫神と同神。月山命(月読命)
アクセス:JR東日本羽越本線 吹浦駅 徒歩約5分

続いて蕨岡口へ。

鳥海山大物忌神社 蕨岡口ノ宮

吹浦口のある吹浦駅の隣、遊佐駅が最寄りの蕨岡口へ。

何はともあれ本殿がでかい。


これだと伝わりづらいですね…。ええ…。

説明によると、”桁行総長は13.8m、梁間の実長も16.9mに及び、床高も2.3mあまり〜”との事。国登録有形文化財にも登録されているとの事。

栄えていた事を伺わせる。神仏習合自体は、社僧もたくさんいらっしゃったんでしょうねえ。

他にも記念碑等見所の多い蕨岡口なのだが、アクセスは少々悪い。一番近い駅から大体5kmあるので、歩くとちょっと大変。大変だった。 バスも無いので、タクシー or レンタサイクルがおすすめ。

祭神:大物忌神(おおものいみのかみ) アクセス:JR東日本羽越本線 遊佐駅 大体駅から5km位。バス等は無いので、タクシー、又はレンタサイクル(駅でレンタルしている)がお勧め。

これで東北も完了。次は富山の予定。

折角Rails 4.2.0 beta1が出たので、個人で使ってるアプリをアップデートしてみました。

bundle update rails実行後rails sを実行すると、Sprockets::Rails::Helper::AssetFilteredErrorでエラーが。

エラー詳細は以下の通り。

"Asset filtered out and will not be served: add Rails.application.config.assets.precompile += %w( bootstrap-theme-white-plum/dist/fonts/glyphicons-halflings-regular.eot ) to config/initializers/assets.rb and restart your server”

sprockets-railsが2.1から、全ての環境でprecompile list必要になった事に伴い、 こちらのコミットで、assets.precompileについてはinitializersに定義するよう修正されたので、エラーメッセージの通りにconfig/initializers/assets.rbにassets.precompileの設定を追加した所、無事に起動しました。

因みに、developmentでもconfig.assets.digestsデフォルトがtrueになるよう修正されているので、ちゃんとprecompileの設定及びassetファイルを使用する場合は、ヘルパーメソッドを利用するよう対応した方が良さ気ですねえ。

この後ちまちま触っていたら何故かredirect_toメソッドがwrong number of arguments (2 for 1)でエラーになる現象が。

こちらは、turbolinksのバージョンアップを行っていなかったのが問題でした。上記エラーが出た場合、turbolinksを2.2.3に上げたらOKでした。

とりあえずはこんな感じで一通り動くようになりました。

次はMajor Featuresを試してみよう。

仕事でやる必要があったのでメモ。

やりたいこと

ログファイルに特定の文字列(例えば、”Error”など)があった場合に、メールで通知を行いたい。

インストール

今回の環境はUbuntuだったので、aptでインストール。

sudo aptitude install monit

設定ファイルの編集

aptでインストールした場合、デフォルトの設定ファイルは/etc/monit/monitrc。これは/etc/init.d/monitで指定されているので、 もしファイル自体はを変更したい場合は、monitファイルのCONFIGを変更してあげればOK。

設定項目については、monitrcについてちゃんとした説明があるので、詳細はそちら参照。参考までに、私が設定した内容は以下の通り。

set daemon 60
set logfile /var/log/monit.log
set idfile /var/lib/monit/id
set statefile /var/lib/monit/state
set mailserver localhost
set eventqueue
    basedir /var/lib/monit/events
    slots 100
set mail-format {
  from: monit@$HOST
  subject: monit alert --  $EVENT $SERVICE
  message: $EVENT Service $SERVICE
                Date:        $DATE
                Action:      $ACTION
                Host:        $HOST
                Description: $DESCRIPTION

           Your faithful employee,
           Monit
}
set alert xxxx@gmail.com  # receive all alerts
include /etc/monit/conf.d/*

ざっくり書くと、

  • daemon: デーモンとして動作させる場合の監視間隔を秒で指
  • mailserver: アラート送信先メールサーバ
  • mail-format: 送信するメールのフォーマット
  • alert: メールの送信先

という感じで。

ログファイルの監視設定

/etc/monit/monitrc自体に直接書けるのだが、一個のファイルに色々と書くと煩雑にで、今回は別ファイルで管理。 /etc/monit/monitrcの末尾にある include /etc/monit/conf.d/* が別ファイルの読み込み処理で、この書き方の場合、 /etc/monit/conf.d/配下のファイルが全て読み込まれる。

なので、そこに適当な名前でファイルを作成し格納する。中身は以下のような感じ。

check file tmplog with path /home/yaginuma/tmp/test.log
    if match "Error" then alert

割と見たまんまな気がする。

1行目は、

CHECK FILE <unique name> PATH <path>

というフォーマットなので、上記サンプルの場合、が”tmplog”、が”/home/yaginuma/tmp/test.log”になっている。

これで”/home/yaginuma/tmp/test.log”に”Error”という文字列が出力された場合、エラーメールが送信される。設定変更後にmonitの再起動を忘れずに。

上記の例だとメールを送信するようにしているが、任意のコマンド実行したりも出来る。詳細はdoc参照。monit便利。

戸田市花火大会

花火

シャッター速度:2.0、f/7.1、ISO:80だとよさげ。

少し調べたのでメモ。

constraintsとは

railsのroutingには”constraints”という機能があり、routingに様々な制限を設定する事が出来る。

設定出来るconstraintsについては以下。

HTTP Verb Constraints

HTTPメソッドでの制限。

match 'users', to: 'users#index', via: [:get, :post]

上記の場合、GETPOSTメソッド以外でusersアクセスしようとするとActionController::RoutingErrorがraiseされる。rails3系から4系に移行する際によく見た書き方ですな。

Segment Constraints

dynamic segmentのフォーマットについて制限を設定する事が出来る。

  get 'users/:id', to: 'users#show', constraints: { id: /[A-Z]\d{5}/ }

上記の場合、”/users/A12345”は通るが、”/users/893”はエラーになる。値を厳密に制限したいときは使える。

なお、正規表現にアンカーは使用出来ない。アンカーを使用すると、ArgumentErrorが起きる

get 'users/:id', to: 'users#show', constraints: { id: /\A[A-Z]\d{5}\z/ }
# => Regexp anchor characters are not allowed in routing requirements: /\A[A-Z]\d{5}\z/ (ArgumentError)

これは、routesが最初にアンカーを設定しており、constraintsでアンカーを設定する必要が無い為、エラーにしているもよう。逆に言うと、部分一致的な事は設定出来ない。(上記の例だと、”/usesr/A123456”はエラーになる。)

Request-Based Constraints

Requestの情報を元にした制限も出来る。Request objectがStringを返すメソッドをconstraintsに設定出来る。

get :users, to: 'users#index', constraints: { port: '3000' }

上記の場合だと、port番号が3000以外の場合エラーになる。他にも、subdomainの値やprotocolでの制限が可能。request objectについて、詳しくはこちら

Advanced Constraints

もっと複雑な事をしたい場合、constraintsに独自のクラスを指定する事も可能。指定するクラスには、matches?メソッドが定義されていればOK。

例えは、特定のIPからのみリクエストを許容したい場合、以下のように設定可能。

class WhitelistConstraint
  IP_LIST = %w(192.168.1.1 127.0.0.1)

  def initialize
  end

  def matches?(request)
    IP_LIST.include?(request.remote_ip)
  end
end


Rails.application.routes.draw do
  get 'admin/index', constraints: WhitelistConstraint.new
end

上記の場合、IPが192.168.1.1、127.0.0.1以外の場合エラーになる。

なお、上記の例だとインスタンスメソッドにしてるが、クラスメソッドでもOK。

class WhitelistConstraint
  IP_LIST = %w(192.168.1.1 127.0.0.1)

  def self.matches?(request)
    IP_LIST.include?(request.remote_ip)
  end
end


Rails.application.routes.draw do
  get 'admin/index', constraints: WhitelistConstraint
end

特に初期化処理が無い場合は、こっちの方がスッキリする気がする。

lambdaでも出来る。

get 'admin/index',  constraints: ->(request) { WhitelistConstraint::IP_LIST.include?(request.remote_ip) }

routingが汚くなってしまうので、余程短くない限りはクラスを作成してmatches?メソッドを定義した方が良いかなあ。

同じconstraintsを複数のroutingに設定する場合、ブロック設定出来る。

  constraints(WhitelistConstraint) do
    get 'admin/index'
    get 'admin/list'
  end

まとめ

あまり使われて無いような気がするんですが、例えば管理画面にアクセスするIPを制限したい、という場合には割と便利かと。
HTTPサーバで設定出来ればその方が良いと思うのですが、例えばHerokuのようなHTTPサーバを触れないPaaSとかでは、controllerにアクセス制限書くより、routingにあった方がスッキリする時もあるあと。

因みに、先に挙げた例だと、WhitelistConstraintクラスをroutes.rbに直書きしているのですが、実際はそんな事をせず、当然別クラスにするのですが、そのファイルをどこに格納するかで微妙に迷っている。

結局、libの下にconstraintsディレクトリを作成しそこに格納しているのですが、もっと良い場所がある、という方がいたら、教えて頂けますと助かります。

minitest-soundというgemを作ったのでご紹介。

内容

名前の通り、minitestのpluginです。ソースはこちら

minitest実行中、及び、テスト成功/失敗それぞれのタイミングでmp3を再生する事が出来ます。それだけ!

mp3の再生には、mpg123というライブラリを使用しています。コマンドラインでmp3再生出来るので便利。

使い方

先に記載した通り、mpg123を使用しているので、mpg123をインストールしてない場合、まずmpg123のインストールをして下さい。 Ubuntuの場合sudo aptitude install mpg123でOK。他のOSも、(多分)パッケージ管理システムからインストール出来る筈。

次に、お決まりの通り、Gemfileにgem 'minitest-sound'の追加及びbundle installを実行して下さい。

最後に、test_helper.rbに以下の内容を設定して下さい。

require 'minitest/sound'

Minitest::Sound.success = '/aaa/bbb/xxx.mp3' # テスト成功時に再生するmp3ファイル
Minitest::Sound.failure = '/aaa/bbb/xxx.mp3' # テスト失敗時に再生するmp3ファイル
Minitest::Sound.during_test = '/aaa/bbb/xxx.mp3' # テスト実行中に再生するmp3ファイル

ファイルのパスは全てフルパスで。以上で設定完了。

後は普通にテストを実行するとmp3が再生されます。再生されない場合、ファイルのパスが間違っている可能性があります。

今後やりたい事

  • テストが100回成功したらマリオの1upのSEを流す、というネタをtwitterで見かけたので同じ事をやりたい
  • mp3ファイルをローカルに置くと、環境が変わった時に困るので、SoundCloud辺りのクラウドサービスから音源を再生出来るようにしたい。ただ、そうすると、今度はアップロードの手間が。うーん。