一分一秒真剣勝負!

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

今年のテーマ

つまり「今年の目標」なんだけど、年明けから暫くはごたごたしてて、そういうものを設定していなかった。というわけで区切りのいい4月で決めました。 「基本を学び直す」 に決定。 何をするかまだ決めてないけど、とりあえずは定期的にホッテントリに書評が上がる「UNIXという考え方」を読み返してみます。

UNIXという考え方―その設計思想と哲学

UNIXという考え方―その設計思想と哲学

Ginza.rb 第8回 Gemfileみせっこ!みんなどんなの使ってます?に先月行ってきた

2月に参加したGinza.rb第8回目についてのエントリー。 書いたのはいいけど、POSTし忘れてました。 というわけでGinza.rbで紹介したgemと紹介し切れなかったgemをまとめました。 全部ではないですが、これってものをピックアップしてます。

Ginza.rbで紹介したgem

seed-fu

seed-fuはseedデータの管理を行うためのgemです。

これに乗り換えたキッカケはRails4でrake db:fixturs:loadを実行してみたらFIXTURES_PATHの指定時にdeprecatedが出た事でした。 (マスターデータをfixtruesでロードしたかった)

Using FIXTURES_PATH env variable is deprecated, 
please use ActiveRecord::Tasks::DatabaseTasks.fixtures_path = '/path/to/fixtures' instead.

FIXTURES_DIRは今まで通りにパラメータで指定できるのに、FIXTURES_PATHは何故かActiveRecord::Tasks::DatabaseTasks.fixtures_pathで指定する方向になるようです。 これはキモいし、なんか不自然な変更なのでまた仕様が変わりそうな予感もする。ならseedでやろうかと思ったのだけど、

rake db:seed # rakeタスク
Rails.application.load_seed # コードで呼び出す場合

どちらもパラメータを受け取らない。実装を見ると、

# File railties/lib/rails/engine.rb, line 538
def load_seed
  seed_file = paths["db/seeds.rb"].existent.first
  load(seed_file) if seed_file
end

"db/seeds.rb"を決め打ちで読み込んでいるのでRailsのseedだとrake db:fixtures:loadの代わりに使う事はできなかった。そこで偶然見つけたのがseed-fuだった。

# rakeタスク
rake db:seed_fu FIXTURE_PATH=path/to/fixtures # パスを指定できる
rake db:seed_fu FILTER=users,articles # 読み込むseedデータを指定できる
# コードで呼び出す場合
SeedFu.seed(fixture_paths, filter) # rakeタスクと同様のオプションを指定可能

という感じでrailsのfixtures:loadとseedのいいとこ取りみたいなライブラリだったので使うことにしました。 パスが未指定の場合"#{Rails.root}/db/fixtures" と "#{Rails.root}/db/fixtures/#{Rails.env}"がデフォルトで設定されているので、環境ごとにseedデータを分けるのも簡単です。production環境のマスターにデータを追加したいなあって時も使えますね。

というわけでseed-fuオススメです。別のエントリーで使い方まとめようかな。

grape

RESTライクなAPIマイクロフレームワーク・・と書かれてますが、 要するにSinatraっぽいAPI専用のフレームワークで、活発に開発が行われています。 Grapeは単体で使用することもできますが、Railsと組み合わせることも可能です。 実際これで某サービスのAPIを実装しました。採用した決め手になったポイントは、

  • Railsのコントローラで作るより高速
  • 実装が読みやすい
  • HTTPリクエストメソッドにPATCHがある(Railsっぽい)
  • Railsと同居できる(ActiveRecordとか呼べる)
  • 最悪やっぱりRailsのコントローラにしようと思った時に、移行作業がそれほど重くなさそう

といったところで、非常に使いやすかったです。 これ流行ってほしいなー。

Ginza.rbで紹介しなかったgem

paper_trail

世代管理用ライブラリ。RailsCastsで紹介されている割には知名度が低い気がする。全く同じ機能をゴリゴリ書いていたプロダクトを思い出して、これを知ってたら工数減らせたなーとか思った。

pundit

権限管理ライブラリ。ポストcancan!最近流行りつつあるようだ。 cancanよりOOPぽく書ける。

まとめ

これぐらいですかね。全部個人的に流行ってほしいなと思ってるgemの紹介でした。

関連URL

Ginza.rb 第8回 Gemfileみせっこ!みんなどんなの使ってます? Ginza.rb 第8回 Gemfileみせっこ!みんなどんなの使ってます? を開催した

生まれて初めて入院して分かった「入院時に必要な持ち物まとめ」

自分は「死ぬ時以外は入院とかしないんだろうな〜」と勝手に思ってたのですが、1月にマイコプラズマ肺炎で入院してました。 生涯初の入院だったので、持っていくべきものとそうでないものの判断が微妙でした。 また入院・・しないのが理想ですが、その時のために「持っていて良かったもの・持っていくべきだったもの」のまとめを書きます。

持っていって良かったものリスト

Kindle Paperwhite

Kindle Paperwhite (第6世代) ―Wi-Fi + 3G

Kindle Paperwhite (第6世代) ―Wi-Fi + 3G

入院したら殆ど1日中寝ているだろうし、時間があるだろうから本を読もう! と、思ってPaperwhiteを持っていったのだけど、肺炎は熱が出るので熱がある程度下がってくるまでは何も読めませんでした。 手術待ちだったり、熱が出ないタイプの病気で入院するならもっと読めたと思う。

iPhone5S(スマートフォン)

f:id:yatmsu:20140219153933j:plain

今入院するなら持っていかないわけがないスマホ。 ネットには繋がるし、有名なウェブサービスのクライアントアプリはあるし、入院中にiPhoneを使っているとそんな当たり前の事が有難いと感じました。 思ったより使わなかったけど、いつでもネットに繋がるという安心感はあったかな。 ガラケー時代に入院しなかった点は良かった・・・のかもしれない。

USBポート付き電源タップ

Multi Extension Cord(ピンク)C150

Multi Extension Cord(ピンク)C150

これを書く必要があるんだろうかと思ったけど、やはり一番重要なものなので。 殆どの病院ではノートPCの持ち込みを禁止しているので、USBポートがついているタイプの電源タップを持ってくるか、アダプタを用意しないと詰みますw 特にガジェットを沢山持っている人は同時に充電する為に複数のポートが付いていた方が便利ですね。

持っていくべきだったものリスト

iPad mini

iPad miniを押します。 殆どの病院では「PC持ち込み禁止」で、今回入院した病院もそうだったんですが、タブレットを持ち込んでいる人がいたので持ってくるべきだったかなあと思いました。 ただ、退院直前までタブレット使いたいなんて元気が無かったし、やっぱり病状次第ですね。

MacBook Air

APPLE MacBook Air 1.7GHz Core i5/11.6/4GB/128GB MD224J/A

APPLE MacBook Air 1.7GHz Core i5/11.6/4GB/128GB MD224J/A

殆どの病院では「PC持ち込み禁止」と書いておきながらこれを押すのは微妙ですが、 タブレットOKだったらもうノートPC使ったって同じでは・・と感じました。 まあバレなければ・・・・。

千円札とか小銭

入院した病院には売店が無く、菓子パンなど全て自動販売機で売っていました。 運良く両替してもらえたけど、病院によっては両替できないかもなので念の為持っていくべきですね。

S字フック

ゴミ箱があったり、またそれを置くスペースがあれば別ですが、ビニール袋を適当な場所にかけてゴミ箱代わりにするのに使っていました。地味だけど便利ですね。 これは入院前は気づかなくて、家族に頼んで買ってきてもらいました。

歯磨きセット一式

売店があるものだと思い込んで入ったらそんなものは無かったので、これも買ってきてもらいました。 一般的な病院なら中で売ってるのだろうか?

というわけで・・・

あまり参考にならなかったかもしれませんが、入院時に必要なものまとめでした。これが役に立たないのが一番いいですね。

入院してなかったら結構忙しいプロジェクトをやっていたはずで、次のプロジェクトは嫌だなあと思っていたのですが、今になってみると肺炎に比べたら忙しい仕事の方が楽ですね。高熱が出るとそもそも普通に思考を巡らせる事が出来ないし、行動にもかなりの制限がかかるし・・・肺炎で入院している方が圧倒的に辛かった。

あえて良かった点をあげるとすれば、健康は財産だなあと実感できたことかな。 ところでマイコプラズマ肺炎って、健康であればあるほど症状が酷いらしいです。マイコプラズマと判明する前に「年の割には立派な肺炎ですね」とか言われるぐらい酷めな症状だったので、自分は健康なんだろうか。確かに健康診断はオールAではある。

Railsのエラーハンドリング

Rails3.2から結構いい感じになったエラーハンドリング

Railsは1.xからやっているけど、気に喰わないのがエラーハンドリング周りだった。 特にRoutingエラーを補足する為に各バージョンごとに対応が微妙に違ったりして、毎回調べたりRailsの実装を追っていた記憶がある。 だけどRails3.2から実装された機能で、個人的にはこれで落ち着いたかなと思えた。 既に4が出ているので今更感があるけど、備忘録として書いておく。 Rails4.0.2,Ruby2.0.0で確認しています。

Release Notesでは以下のように書かれている。

Added config.exceptions_app to set the exceptions application invoked
by the ShowException middleware when an exception happens.
Defaults to ActionDispatch::PublicExceptions.new(Rails.public_path).

つまり、例外発生時に呼ばれる例外処理アプリケーションを config.exceptions_app で設定できるようになった。 デフォルトではActionDispatch::PublicExceptions.new(Rails.public_path)が設定される。

どうやって使うか

色々と調べた結果、ActionDispatch::Routing::RouteSetをセットしてやるのが一番シンプルかなーと思った。 まずはself.routesをセット。

# config/application.rb
config.exceptions_app = self.routes #=>ActionDispatch::Routing::RouteSet

で、例外処理用のコントローラを作成しておく。

# app/controllers/erros_controller.rb
class ErrorsController < ApplicationController
  def not_found
    render status: 404
  end

  def internal_server_error
    render status: 500
  end
end

最後にroutes.rbで各httpステータスコードを判定し、ErrorsControllerの各メソッドを指定してやる。

# config/routes.rb
  get '/404', to: 'errors#not_found'
  get '/500', to: 'errors#internal_error'

他のやり方

self.routes以外を指定する事も当然出来る。 というかRackアプリを指定できるのでRailsで無くてもOKです。 例えば以下の様な感じ。

# config/application.rb
config.exceptions_app = ->(env) { ErrorsController.action(:error_page).call(env) }

明確にエラーコードを表示したいウェブアプリだと使うかも。

思うこと

エラーハンドリングに関してはRails newした時に雛形を作るなどしてしまってもいいのではと思った。フリーランスで働いていた時に、途中から入ったプロジェクトの場合、エラーハンドリングの実装方法がバラバラで、その内容によっては無駄に工数がかかるケースもあったので。 ま、Rails is omakaseなので嫌なら使うなって話ですが。

Capistrano3が良さげ

CapistranoのVersion3がリリースされてますね。変更点は以下のサイトに大量に書かれています。
Capistrano Version 3 ReleaseAnnounceme

変更点が多過ぎて全部まとめるのは諦めたので、個人的にこれはいいなーと思った点を上げます。

良かった変更点

  • マルチステージをデフォルトでサポート

もうこれでcapistrano-extはいらない。まあ、これは標準サポートされてもいいですよね。

  • デプロイの高速化

確か以前はコマンド1回実行毎にsshのセッションを貼り直していたので遅かったはず。SSHのライブラリを変更したのと同時にココらへんも改善されたのかも。ただ、やっぱりRailsをデプロイする時はassetsのコンパイルでちょっと止まりますね。

  • 実装が見やすくなった

capistrano2はネットにドキュメントが少なくて結局実装を読む事になる場合が多かったのですが、2と比較すると3の方が見やすくなってました。これは助かります。

  • linked_files, linked_dirs

これ凄い便利です。シンボリックリンクを貼りたいファイルがあった時に短く書ける。確かcapistrano2の時は確か無かったと思いますが・・どうなんだろ。
例えばdatabase.ymlのようにgitなどで管理したくないファイルを渡してやると、

set :linked_files, %w{config/database.yml}

/shared/config/database.ymlから/deploy先のバス/current/config/database.ymlにシンボリックリンクを貼ってくれる!2まではrunとかで普通にコマンドを書いていたので、これは楽です。やっぱりこういうファイルってshared配下に置く人が多いんだろうか。linked_dirsもlinked_filesと同じ感じです。

デプロイスクリプトのサンプル

とりあえずRailsアプリをデプロイするスクリプトを書いてみた。ただファイルを置くだけなんで、Webサーバの再起動とかプロセスのリスタートとかは書いてません。

Gemfile

  gem 'capistrano', '3.0.0', github: 'capistrano/capistrano'                                                                                                                                                           
  gem 'capistrano-rails'                                                                                                                                                                                               
  gem 'capistrano-rbenv', github: 'capistrano/rbenv'                                                                                                                                                                   
  gem 'capistrano-bundler', github: 'capistrano/bundler' 

Capfiile

require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/console'
require 'capistrano/rbenv'
set :rbenv_type, :user
set :rbenv_ruby, '2.0.0-p247'
require 'capistrano/bundler'
require 'capistrano/rails'

# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r }

config/deploy.rb

set :application, :sample
set :repo_url, 'git://hogehogehoge.com/hoge.git'
ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp }

set :deploy_to, '/deploy/to'
set :scm, :git

set :pty, true

set :linked_files, %w{config/database.yml config/resque.yml}
# set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}

set :keep_releases, 10

config/deploy/production.rb

set :stage, :production

# Simple Role Syntax
# ==================
# Supports bulk-adding hosts to roles, the primary
# server in each group is considered to be the first
# unless any hosts have the primary property set.
role :app, %w{app@hoge1 app@hoge2}
role :web, %w{app@hoge1 app@hoge2}
role :db,  %w{app@hoge1}, primary: true

# you can set custom ssh options
# it's possible to pass any option but you need to keep in mind that net/ssh understand limited list of options
# you can see them in [net/ssh documentation](http://net-ssh.github.io/net-ssh/classes/Net/SSH.html#method-c-start)
# set it globally
set :ssh_options, {
  keys: %w(/home/app/.ssh/id_rsa),
  forward_agent: true,
  auth_methods: %w(publickey)
}
# and/or per server
# server 'example.com',
#   user: 'user_name',
#   roles: %w{web app},
#   ssh_options: {
#     user: 'user_name', # overrides user setting above
#     keys: %w(/home/user_name/.ssh/id_rsa),
#     forward_agent: false,
#     auth_methods: %w(publickey password)
#     # password: 'please use keys'
#   }
# setting per server overrides global ssh_options

# fetch(:default_env).merge!(:rails_env, :production)

サーバの再起動とか全くやってないのであまり参考にはならない。。
ま、ドキュメント読んだりちょっといじってみた結果、実行速度を理由にminaを使うならCapistrano3を使った方がいいかなと感じました。十分早いし、ちょと複雑な事をminaでやろうとすると時間がかかったりするんで。

追記

いいまとめエントリーきました!
Capistrano 3への手引き - 今日のごはんは素麺です http://takkkun.hatenablog.com/entry/2013/10/12/Capistrano_3%E3%81%B8%E3%81%AE%E6%89%8B%E5%BC%95%E3%81%8D