システム・PC

Rails4.2 + Mongoにしました

Railsを4.2にした序でにMySQLを捨ててMongoにしてみました。

一応動いている模様。

chromebook ASUS C300でdeveloper modeに入るメモ

リカバリーメディアを作成してから

esc + F3 + 電源

同時押し

サーバが逝く

AJPG-2fjq02j2dkc8.jpg

HPのProliant ML115が死にました。

暫く電源を切って床の上におきっぱで先日ルータとして復活したんですが早くも死亡。電源を交換してみたら動いたのでどうも電源が逝ったようです。ここ数日暑かったですからね。CPUの温度はチェックしていたのにまさか電源とか電源にはセンサーないもんなぁ・・・

そういや青森でもHPのサーバが先日逝ったんですよね。あれも電源だったのかな?(調査する時間がないので、そのまま廃棄)

で、電源を交換しようと螺旋を星型ドライバーで外そうとしたんですが電源の螺旋がバカになってるのかドライバーがちょっと小さいのか一ヶ所しか回らないんですよね。しかも別の電源(いわゆる普通にショップで売ってる電源)はネジ穴の位置が合わなくて結局写真のように応急処置。

当面これとエアコン強めで凌ごう


 

RailsのAction Cache

RailsでAction cacheでlayoutの中身だけをchaceする Action cacheはactionを丸々キャッシュするのですが、 フィルターは実行してくれるのでそこに「キャッシュを何時どうやって消すか?」という ロジックを書くことが出来るという利点があります。

また、Layoutの中身だけキャッシュするという機構があるので、レイアウトの外側に ログインしているユーザ名を書いたりする動的なページも作ることができます。

これらどちらも Page cacheでは難しい問題なんですよね。 さて、このAction cacheですが 3.Xまでは標準パッケージに含まれていましたが、 4.xからは標準パッケージに含まれなくなったので、gemで追加してやる必要があります。 やり方は他と同様 Gemfileに次の一行を書いてbundleをしなおすことでOKです。

gem 'actionpack-action_caching'

使い方ですが、controllerにキャッシュしたい actionを以下のように書けばOK

  caches_action :show

これで 初回アクセス時のみshow アクションが実行され、2回目からは 初回アクセス時に renderされたHTMLが帰ってきます。 内容が更新されない場合は、これだけでいいのですが更新もある場合は 以下のように chaceのパラメータに何か更新する情報を渡してやるのがよいでせう。

caches_action :show, cache_path: Proc.new{ params.merge(:t => @blog.updated_at.to_f) } 

@blogが更新される度に updated_atが更新されれば、 cache_pathパラメータが 毎回変わるので古いキャッシュが使用されることなく新しいキャッシュファイルが 作られるというわけです。 ただしこれは tmp/cachesの下にどんどんファイルが溜っていくので、 定期的に日付を見てファイルを削除してやるロジックが必要になります。 Layoutの中身だけCacheしたい場合はさらに layoutパラメータを追加し

  caches_action :show, layout: false, cache_path: Proc.new{
   params.merge(:t => @blog.updated_at.to_f)
  }

とします。但しこの場合

  • Controllerはデフォルトのレイアウトを持っていなければならない
  • render時に layoutのパラメータを指定してはならない

という条件がつきます。Filterの評価が全て終ったあとに、どのlayoutが 使われるのあ分からないとキャッシュできないので、これは致し方のないところで ありましょう。 通常はデフォルトのLayoutは applicationになっていると思いますが、 例えばuser毎にlayoutを変える必要がある場合は

  layout :custom_layout
...
...
  private
  def custom_layout
    @user.laytout
  end

のように layoutにメソッド名をシンボルで指定してやればOKです。 さて、ここまで書いて、いろいろなところで @userやら @blogなどというインスタンス変数が登場してますが、 これらを Actionで取得することはできません。つまり、

  def show
    @blog = Blog.find(params[:id])
  end

とか書くのはNGです。何故なら cacheを使うかどうかは actionよりも先に実行されるので、 その前に@blogなどは取得できてないといけないわけです。 つまり、

  before_action :set_blog, if: [:show]

  private 
  def before_action
    @blog = Blog.find(parmas[:id])
  end

のようなFilterを書いておかないといけないと。 また、Layoutの外側に書く内容も当然filterで全て処理をしておかない いけなくなります。 結果 Action本体よりも Filterばっかり書くハメになり、コードの見通しが悪くなるという 問題があるんですよね。

Windows Live Mailが postfix+dovecotで使えなかった件

Outlook Expressの時代からMicrosoftのメールソフトには煮え湯を飲まされており「Thunderbird使えばいいよね。」みたいな解法を取ってきたオイラですが、流石に人様にサーバを提供するとなるとそういうわけにもいかず、まぁしかしWindowsだってXPが登場して10年にもなるわけで、しかもスマフォやらが出て来た昨今、Submissionとか対応してるよね・・・と思ってたんですが、なんかやっぱり癖があるらしいです。少なくともデフォルトの設定では動かんかった。STARTTLSしてくれん・・うーむ。どうしたものか?

まぁ、でも今はグーグル先生もあるし、世界中の人が悩んでるはずだから簡単に解答見つかるよね。とか思ってたんですが、これが案外無いのなね。ありがちなのが「Thunderbirdで問題なかった」「俺のIPhoneでは問題なかった」とかで・・・むしろ情報の少なさと質の低さに驚いた。

「メールサーバなんて自分で建てなくていいだろ!gmail使えよ!」

そういう時代すかね?

で、前置き長くなったけど、結論を言うと dovecotのauth-mechanizmsに loginを追加したらうまくいきました。

auth_mechanisms = plain login cram-md5

こんな感じです。

RailsのFragment Cache

Viewだけで Fragmentキャッシュをするには

<% cache key do %>
hogehoge
<% end %>

で良いのですが、例えばControllerでも負荷の重いところをスルーさせようとするとViewとControllerで深い連携が必要になるからゴチャゴチャしはじめるます。MVCモデルが裏目に出ているとも言えましょう。ちなみに、これをチェックするにはコントローラ側で

unless fragment_exist?(key)
  #負荷のかかる処理
end

とかやればいいんですが、デフォルトの FileCacheだとハッシュ関数でダイジェスト文字列をkeyの後ろにつけてしまうので、このコードではこの処理は毎回実行されてしまいます。この文字列を Controller側で知る方法が分からないので困りました・・・View側での対処は簡単で

<% cache key, skip_digest: true do %>
hogehoge
<% end %>

のように skip_digestオプションを指定してあげればOK。

こんなことするくらいならAction cacheのほうが簡単かな?

FreeBSD 10.0-RELEASE

ZFSでスナップを取って、万が一動かない状態になってもなんとかなるであろう。という状況にしてコマンドをタイプ

# freebsd-update upgrade -r 10.0-RELEASE

さてどうなることやら・・・と思ってたら

Cowardly refusing to proceed any further.

とな。どうもfreebsd-updateがちょっと古いっぽい。ということで単純に

# freebsd-update fetch # freebsd-update install

でまずは9.2の最新バージョンにする。これで、うまく進行しそうだ。しかしサーバ重いな・・こりゃいつ終わるかわからんぜ・・・

いろいろ不具合があるもんだ

とりあえず、turbolinksというのでハマりました。

ページをクリックで移動すると、ソーシャル系のボタンが表示されないという現象が起きていたわけですが、この原因がturblinks。、

これはRails4の標準なんですが、簡単にいうとページ遷移をするときにAjaxで遷移先コンテンツを取得し、(可能ならば)ページ移動することなく高速にページを切り替えるというものなんですが、このため bodyに対して読み込み済みというイベントが発生しないためボタン系のスクリプトが動かず描画されなかったと。
 

とりあえず自サイト内だけならいくらでも対応できるんですが、他サイトとかどうすりゃいいのかさっぱり分からないので、application.jsよりエイヤっと消すことで対処しました。後ろ向き

HTTP Access Controlによるクロスサイト HTTPリクエスト制御のメモ

CORS(Cross-Origin Resource Sharing)とも呼ばれるようですが、この技術についていろいろ調べることがあったのでメモ書き。(最近いろいろ堕落してるんでサンプルコードはjQuery使用前提で)

例えばあるサイト(example.com)のHTMLに以下のようなスクリプトを書いた場合エラーとなり期待した動作をしてくれません。

<script type="text/javascript">
jQuery(function($){
  $.ajax("http://other.com/test/other", {
  }).done(function(data, textStatus, jqXHR){
    alert(textStatus);
    $('#res').html(data);
  }).fail(function(jqXHR, textStatus, errorThrown){
    alert(textStatus);
  });
});
</script>

<div id="res">
</div>

これは、XMLHttpReuqestの送り先のホストが example.com上に存在しないから です。これが自由に出来てしまうといろいろと困った問題が起きるのでこんな ことになっているのですが、そうは言っても異るドメイン間でデータを共有したいというシーンは結構あったりするのもまた事実です。

そんな要求もあったのか、モダンなブラウザでは Access-Controll-Allow-Originヘッダをサーバ側で付けることにより、異なるドメイン間でもリクエストを受けとり処理ができるようにすることができます。

記の例についていえばXMLHttpRequestでリクエストを投げるコンテンツ (つまり http://other.com/test/other )のレスポンスヘッダに

Access-Control-Allow-Origin: *

を追加するとOKです。ちなみに「*」はどのホストからのリクエストでも 許可するという意味です。特定のホストからのリクエストのみ許可する 場合は

Access-Control-Allow-Origin: http://example.com

のように返します。

ちなみにこのような異なるドメインにリクエストを投げる場合、 XMLHttpRequestはクレデンシャル(つまり資格情報、もっとありていに言えば Cookieとか)の情報を送りません。

クレデンシャルをもリクエストで送りたい場合は example.com 内での XMLHttpRequestオブジェクトのプロパティ withCredentialstrue にしてさらに other.comのレスポンスヘッダに

Access-Control-Allow-Credentials: true

を追加してやる必要があります。この場合「*」のようにどこからでもOK というのは設定できないので、明示的にホスト名を書く必要があります。 参考までに上記のヘッダを jQueryで実現するには以下のようになります。

<script type="text/javascript">
jQuery(function($){
  $.ajax("<%= @other_url %>/test/other", {
    xhrFields: {
      withCredentials: true
    }
  }).done(function(data, textStatus, jqXHR){
    alert(textStatus);
    $('#res').html(data);
  }).fail(function(jqXHR, textStatus, errorThrown){
    alert(textStatus);
  });
});
</script>

<div id="res">
</div>

この機能がいつからあるのかは知りませんが少なくともW3Cを見る限りだと 2005年あたりから議論が始まりの2008年の9月のドラフトでこのヘッダ名になっ ているようです。Firefoxなどでは結構古くから実装されているみたいですね。 IE10でもサポートされているようなのでXPが死んだら広く使われるようになる??かもしれません。

参考リンク

サンプルおいときました

https://github.com/i10a/access_controll_test

Ruby on Railsで独自のテンプレートハンドラを追加する

viewにおいて普通は拡張子 .erbをつけてると思いますが、これはerbをハンドルするハンドラで描画するという意味。ここに独自のハンドラを追加するにはこうやるとよいようです

適当にハンドラクラス(たとえばHoge::Handler)というのを作り

ActionView::Template.register_template_handler(:hoge, Hoge::Handler)

で登録する。これで拡張子hogeのついたviewはHoge::Handlerで描画します。はい終了。Rails3.2で確認しました

で、肝心のHoge::Handlerなんですが

module Hoge
  class Handler
    def self.call(template)
      new.call(template)
    end

    def call(template)
      "'" + template.source "';"
    end
  end
end

のように self.callを実装するだけでよいようです。(何も変換せずにそのまま出力するコードですが) なお、上のコードだとシングルクオートやバックスラッシュが入ってきたときにエラーになるので、そこのとこだけちょっと工夫する必要がありますが本質的ではないので割愛しました。