@ka2n

Technology and beer

Martiniのrender+ sessionauthでテンプレートからログイン中のユーザーを取得する

martini-contrib/rendermartini-contrib/sessionauth を組み合わせて使っている時に毎回各ハンドラでユーザーをrenderに渡していた。

関係ないところは省いてあるけどこんな感じ

func main() {
  m := martini.Classic()
  m.Use(sessionauth.SessionUser(GenerateAnonymousUser))
  m.Use(render.Renderer())
  m.Get("/private", GetPrivate)
  m.Run()
}

func GetPrivate(r render.Render, user sessionauth.User) {
  r.HTML(200, "private", map[string]interface{}{"User": user.(*UserModel)})
}

private.tmpl

{{if .User.IsAuthenticated }}
ログイン済み
{{end}}

まぁこれでも良いのだけどいちいち書くのが面倒なのでテンプレート関数を定義してユーザーを取得できるようした。 html/templateの機能だけどもちろんrenderから使える。

func main() {
  m := martini.Classic()
  m.Use(sessionauth.SessionUser(GenerateAnonymousUser))
  // ダミーの関数を追加しておく
  m.Use(render.Renderer(render.Options{
    Funcs:  []template.FuncMap{{"currentUser": func() *UserModel { return nil }}},
  }))
  // ミドルウェアで関数を上書きする
  m.Use(func(r render.Render, u sessionauth.User) {
    r.Template().Funcs(template.FuncMap{
      "currentUser": func() *UserModel { return u.(*UserModel) },
    })
  })

  m.Get("/private", GetPrivate)
  m.Run()
}

func GetPrivate(r render.Render, user sessionauth.User) {
  r.HTML(200, "private", nil)
}

private.tmpl

{{if currentUser.IsAuthenticated }}
ログイン済み
{{end}}

あまり良い方法ではない。 まずダミーの関数で名前だけを登録しておいて、次にミドルウェアとしてsessionauthからユーザーを取り出しrenderのテンプレート関数を上書きするという動きになっている。

元ネタ Allow injecting into helper functions · Issue #3 · martini-contrib/render · GitHub