今更ながらシリーズ(2) StringInquirer
Rails.env == 'production'
という式は、
Rails.env.production?
と書ける。これは Rails.env が単なる文字列ではなく、ActiveSupport::StringInquirer という String を継承したクラスに変換されているから。
ActiveSupport.StringInquirer.new("foo").foo? #=> true
ちなみに、Rails 3.1 では、String#inquiry で String から StringInquirer を生成できる。
Rails.version # => "3.1.0.beta1" s = "hoge".inquiry # => "hoge" s.class # => ActiveSupport::StringInquirer s.hoge? # => true s.fuga? # => false
今更ながら CaptureHelper
本当に今更だけど CaptureHelper なる存在を知った。
maiha 氏が説明してる程度に昔からある。なんてこった。
view:
<% div_wrapper do %> <p>ほげほげ</p> <% end %>
helper:
def div_wrapper(&block) render :inline => "<div>#{capture(&block)}</div>" end
結果
<div><p>ほげほげ</p></div>
Rails3 で routes.rb を分割・追加する
故あって routes.rb を routes/frontend.rb と routes/backend.rb に分割したいとする。
とりあえず、 routes.rb の中で require なり load なりしてもよいが、これだと開発中に routes/frontend.rb を編集しても、再起動しない限り反映されない。
SampleApp::Application.routes.draw do # : # : end require_relative 'routes/frontend.rb' require_relative 'routes/backend.rb'
そうしないためには、該当のファイルを routes ファイルパス設定に追加する。
config/application.rb の中で以下のように記述する。
module SampleApp class Application < Rails::Application # : # : その他の設定 # : config.paths.config.routes.concat Dir[Rails.root.join("config/routes/*.rb")] end end
あるいは追加したいパスが一つならば、 config.paths.config.routes << Rails.root.join("config/routes/aroute.rb") としてもよいようだ。
(config.paths.config.routes は Rails::Paths::Path なのでそのメソッドを参照。)
そして各ファイルに普通に routes.rb のようにルーティングを記述すればよい。
読み込まれる順番に注意。追加する際と 逆順で読み込まれる 。すなわち、先の例であれば以下のような順で load されることになる。
- config/routes/frontend.rb
- config/routes/backend.rb
- config/routes.rb
Pound で Proxy させるとデフォルトではバックエンドよりタイムアウトの設定が短い件
[UserAgent] - Pound - Varnish - AppServer
例えば↑のような HTTP Proxy が連なった構成のとき、AppServer がうっかり固まってると(ここでは Read timeout を想定)、プロキシがそれぞれタイムアウトするわけだけど、 Pound はデフォルト設定では 15 秒後に 500 (!!) レスポンスを返す。このデフォルト値は Varnish (60s) や Nginx (60s), Apache+mod_proxy (300s) のデフォルト値より短く、またそれらが返すステータスコード 503 と異なる。
返すステータスコードはパッチをあてない限り変更できないので、通常はタイムアウト値をそれらの設定より伸ばすしかない。
TimeOut 305
こういうこともあるので、HTTP Proxy のタイムアウト値の設定については、デフォルト値を使わずにちゃんと要件に合わせて設定を書く必要がある。(もちろん、タイムアウトにならないよう AppServer を十分速くするのは前提。)
escape_utils
escape_utils を以前紹介したけど、その時のバージョンはバグがあったので、0.2.1 以上にした方がよいです。特に日本語のリクエストがあった場合に、情報の欠落が発生する可能性があります。
gem "escape_utils", ">= 0.2.1"
あとは実は厳密には Rack の unescape_url とはエンコーディング関係で挙動違うんだけど、今のところそれは問題になっていないはず。
Model.scoped
ActiveRecord で Model の空のリレーションを作成するには、scoped メソッドを使うらしい。(WEB-DB PRESSに載ってたらしいけど引っ張り出せない。)
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/named_scope.rb
ri scoped する。
Returns an anonymous scope. posts = Post.scoped posts.size # Fires "select count(*) from posts" and returns the count posts.each {|p| puts p.name } # Fires "select * from posts" and loads post objects fruits = Fruit.scoped fruits = fruits.where(:colour => 'red') if options[:red_only] fruits = fruits.limit(10) if limited? Anonymous scopes tend to be useful when procedurally generating complex queries, where passing intermediate values (scopes) around as first-class objects is convenient.
こんな感じか。
# model class Item < ActiveRecord::Base # .. def self.rel(condition = nil) if condition.present? where(condition) else scoped end end end # controller cond = { :cond => :somthing } @items = Item.rel(cond).paginate(:page => 1) #...
Vim から Evernote にポスト
とりあえず今開いてるバッファの内容を Evernote に送り付けるスクリプト。
_vimrc で設定しておけば一発で Evernote 行きだ。
nmap ,n :call WinVimToEver()<CR>
Mac だと全然違うアプローチが必要そうなので Win って接頭辞つけた。
winvimtoever.vim:
" winvimtoever.vim " vim script, send current buffer to evernote if !exists("g:winVimToEverUseFilename") let g:winVimToEverUseFilename = 0 endif if !exists("g:winVimToEverPath") let g:winVimToEverPath = 'C:\Progra~1\Evernote\Evernote3.5\ENScript.exe' endif if !exists("g:winVimToEverNote") let g:winVimToEverNote = "" end if !exists("g:winVimToEverAttachment") let g:winVimToEverAttachment = 0 endif function! WinVimToEver() if g:winVimToEverUseFilename let title = expand("%:t") else let title = iconv(getline(1), &fileencoding, "cp932") endif " TODO: tag "let tag = ... let tmpdir = tempname() call mkdir(tmpdir) let bodyfile = fnamemodify(tempname(), ":p:r").'.txt' let lines = getline(1, line("$")) let encoded = iconv(join(lines, "\r\n"), &fileencoding, "cp932") call writefile(split(encoded, "\r\n", 1), bodyfile, "b") let cmd = g:winVimToEverPath.' createNote /s '.shellescape(bodyfile).' /i '.shellescape(title) if g:winVimToEverAttachment let filename = expand("%:t") if filename == '' let filename = 'attachment.txt' end let tmpfile = tmpdir . '\' . filename call writefile(split(encoded, "\r\n", 1), tmpfile, "b") let cmd = cmd.' /a '.shellescape(tmpfile) end if g:winVimToEverNote let cmd = cmd.' /n '.shellescape(g:winVimToEverNote) endif let ret = system(cmd) " FIXME! call system("rmdir /S /Q ".shellescape(tmpdir)) call delete(bodyfile) endfunction
https://github.com/holysugar/winvimtoever に置きました。
参考にしたもの