Rack::GoogleAnalytics

leehambley/rack-google-analytics

この Rack Middleware は、 production 環境のすべての HTML を返す URL に Google Analytics を組み込みたいというニーズがあったときに便利。以下サンプル。

Gemfile:

gem 'rack-google-analytics', :require => 'rack/google-analytics'

config/environments/production.rb:

config.middleware.use Rack::GoogleAnalytics, :tracker => 'UA-xxxxxx-x'

すべての layout ファイルに入れて回ったりしないので楽だし DRY。config.middleware.use を config/environments/production.rb に書くのがポイント。development.rb や application.rb に書けば、当然その環境でも有効になる。

この middleware は Google Analytics をすべてのレイアウトで間違いなく挿入する一つの方法になるのではと。(他の手段としては、個人的には、 application.js で require されるように asset pipeline 経由で書いてしまうのもアリだと思う)

ただし

Rack Middleware のレイヤーで HTML を操作することの是非は検討すべきかなと思うし、許容できる場合のみに使用すべきかと思う。

備考

類似品として grays/rack-google_analytics というのもある。(async で打てないので実用はむずかしいか?)

Rack::Access で IP アドレス制限

Rails アプリケーションで IP アドレス制限が必要になった際には、基本的に上位のリバースプロキシ(Apache とか Nginx とか)で行うことが多いと思いますが、一方で Rails 本体で制限をかけなければならないこともあります(Heroku だとか)

でもそれを Rails の controller 層とかで実装するのはちょっと嫌ですよね。特にビジネスロジックではないことが多いですし。

というわけで、IP アドレス制限を Rack Middleware 層で実装した Rack::Access というモジュールを使ってみました。これは GitHub - rack/rack-contrib: Contributed Rack Middleware and Utilities に含まれています。使い方は Gemfile に書いて bundle して config/application.rb に設定を書いて完了です。

Gemfile:

gem 'rack-contrib', :require => 'rack/contrib'

config/application.rb

config.middleware.use "Rack::Access", '/' => [ '127.0.0.1',  '192.168.1.0/24' ]

これで 127.0.0.1 あるいは 192.168.1.0/24 以外からのアクセスには Forbidden を返すようになります。

当然、実行環境によって異なる制限をかけることになると思います。それぞれ environments/ 以下に書いてもいいと思うのですが、面倒なので自分は YAML に書きました。

config/application.rb

config.middleware.use "Rack::Access", YAML.load(open(Rails.root + "config/access.yml", &:read))[Rails.env]

config/access.yml

localnet: &localnet
  /:
    - 127.0.0.1
    - 192.168.1.0/24

development:
  <<: *localnet

test:
  <<: *localnet

production
  /:
    - xxx.xxx.xxx.xxx # 公開対象アドレス

動的に制限を変更するという使い方をしたければもう少し複雑にしなければいけませんが(一応できるはず)、イントラ向けアプリなどではこの程度で十分ではないでしょうか。

もちろん Rack middleware なので、 Rails 以外のアプリケーションでも同様に使えるのがいいですね。

shoulda-mathcers での validate_uniquness_of の注意点

class User < ActiveRecord::Base
  validate :name, :unique => true 
end

ActiveRecord の↑のようなモデルの spec として、shoulda-matchers の validate_uniquness_of を使うことがある。

このときこんな風に書くと、場合によって通ったり通らなかったりするので注意が必要。

describe User do
   it { should validate_uniqueness_of(:name) }
end

validate_uniquness_of のドキュメントには以下のようにある。

      # Internally, this uses values from existing records to test validations,
      # so this will always fail if you have not saved at least one record for
      # the model being tested, like so:
      #
      #   describe User do
      #     before(:each) { User.create!(:email => 'address@example.com') }
      #     it { should validate_uniqueness_of(:email) }
      #   end
https://github.com/thoughtbot/shoulda-matchers/blob/master/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb

てなわけで、( factory girl と組み合わせて ) こんな感じでないと安定しなかった。

describe User do
  before { create :user }  
  it { should validate_uniqueness_of(:name) }
end

元のでも他の spec の都合でレコードが残ってたりする場合に通ったりするので、「手元で通るけど jenkins だと通らないよ!」というパターンになるので要注意。

FactoryGirl の新しいインタフェースに移行したときのメモ

えいっと新しい FactoryGirl に移行して、新しいインタフェースに対応してみた。どう移行したかは GETTEING_STARTED.md を読んでその通りに定義部分と利用部分を修正した。詳細は省く。

……が、こんな感じのエラーに悩む。

....../ruby-1.9.2-p290/gems/factory_girl-2.1.2/lib/factory_girl/registry.rb:38:in `add_as': Already defined: user (FactoryGirl::DuplicateDefinitionError)

多重定義と言っているが、特に複数個定義していない。

  • 古いインタフェースが混じってたのでそれを統一したり
  • factory の継承をやめてみたり
  • alias をやめてみたり

してみたがダメで仕方なくソースまで潜る。DIVE TO THE NIGHT.

結論としては、 spec_helper.rb で spec/factories を require していた行があったので、削除して解決した。

require Rails.root.join("spec/factories.rb")

FactoryGirl は factories ファイルを load するので注意なのだな。

packed_field gem

RailsActiveRecord::Base.serialize を(仕方なく)使う機会があったが、使い方が気に食わなかったんでさくっと Wrapper を書いたりした。

名前をやっつけすぎたと思った。あとさりげなく jeweler 初めて使った。

あたりを参考にさせていただきました。

Capistrano で GitHub の CA Cert 関連のエラーが出てしまうとき

対象: capistano で Rails をデプロイして bundle install の際に GitHub で証明書のエラーになっちゃう人

require 'bundle/capistrano'
*** [err :: user@xxx.xxx.xxx.xxx] error: SSL certificate problem, verify that the CA cert is OK. Details:*** [err :: user@xxx.xxx.xxx.xxx] error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed while accessing https://github.com/holysugar/sandbox.git/info/refs
*** [err :: user@xxx.xxx.xxx.xxx]
*** [err :: user@xxx.xxx.xxx.xxx] fatal: HTTP request failed
 ** [out :: user@xxx.xxx.xxx.xxx] Git error: command `git clone 'https://github.com/holysugar/sandbox.git' "/u/app/shared/bundle/ruby/1.9.1/cache/bundler/git/sandbox-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --bare --no-hardlinks` in directory /home/user has failed.

選択肢は

  • 証明書の検証を無視する
  • 証明書を追加する

前者はいろいろなことを放棄していると思うので後者を選びたい。

一般的には http://sakuratan.biz/archives/2812 などに解決策がある。だけど、全部のサーバーで(例えば) /etc/pki/tls/cert.pem 書き換えたりするのは面倒。

結局のところ bundle install のタイミングで証明書が使えればいいので、追加したい証明書をレポジトリのどこか(ここでは config/etc/pki/ourcert.pem とする)に入れた上で、さらに deploy.rb に以下の設定を行う。

set (:bundle_cmd) { "GIT_SSL_CAINFO=#{release_path}/config/etc/pki/ourcert.pem bundle" }    

これで bundle コマンド中の git コマンドでは自動的に参照されるようにして、まとめて解決できた。:)

証明書は Firefoxhttps://github.com/ にアクセスして 「アドレスバー左の鍵クリック - 証明書を表示 - 詳細 - エクスポート - 証明書パスを含む X.509 証明書(PEM)」 と選択していけば保存できる。