👆

Sinatraでtiltを使う場合には .render(self) する

2022/08/31に公開

困ったこと

tilt-jbuilderを使ってSinatraからjbuilderを呼び出そうとしたときのこと。

class Application < Sinatra::Base
  get '/ping' do
    template = Tilt::JbuilderTemplate.new("views/ping.json.jbuilder")
    template.render
  end
end
json.code params['code']

bundle exec rackup -p 3000 でサーバーを起動して curl http://localhost:3000/ping?code=123 としても、paramsが未定義のエラーになる。

どうしてparamsが使えないのか。erbだとどうか?

  • erb :'ping' → parmasは使えた
  • Tilt::ERBTemplate.new('views/ping.erb').render → paramsは使えなかった。

Tiltのテンプレートを直列使ってrenderするとparamsが使えないということは、Sinatraが内部でゴニョゴニョしてparamsを使えるようにしていることになる。

https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb

erbメソッドはrenderメソッドにそのままスルーパスしてるだけ。

    def erb(template, options = {}, locals = {}, &block)
      render(:erb, template, options, locals, &block)
    end

renderメソッドは、Templateクラスを見つけてrenderしているだけ

        template        = compile_template(engine, data, options, views)
        output          = template.render(scope, locals, &block)

このscopeとlocalsが何かというと・・・

locals          = options.delete(:locals) || locals         || {}

scope           = options.delete(:scope)          || self

localsは特になにも指定がなく空配列だが、scopeに self (SinatraのApplicationクラス)が渡されている。

つまり...

これでいい

  get '/ping' do
    template = Tilt::JbuilderTemplate.new("views/ping.json.jbuilder")
    template.render(self)
  end
% curl http://localhost:3000/ping?code=123
{"code":123}

Discussion