【问题标题】:clojure, enlive, multi-siteclojure, 活跃, 多站点
【发布时间】:2012-11-26 04:27:41
【问题描述】:

尝试根据 :server-name 在请求中返回的内容加载特定模板:

(ns rosay.views.common
  (:use noir.core)
  (:require [noir.request :as req]
            [clojure.string :as string]
            [net.cgrand.enlive-html :as html]))

(defn get-server-name
  "Pulls servername for template definition"
  []
  (or (:server-name (req/ring-request)) "localhost"))

(defn get-template
  "Grabs template name for current server"
  [tmpl]
  (string/join "" (concat [(get-server-name) tmpl])))

(html/deftemplate base (get-template "/base.html")
  []
  [:p] (html/content (get-template "/base.html")))

它适用于返回 /home/usr/rosay/resources/localhost/base.html 的 localhost,但是当我针对不同的主机进行测试时说“hostname2”,我看到 get-template 在哪里查看 /home/usr/ rosay/resources/hostname2/base.html 但是当它在浏览器中呈现时,它总是指向 ../resources/localhost/base.html。

是否有宏或不同的方式来处理这个用例?

【问题讨论】:

  • 问题是 deftemplate 是一个宏,所以它是在编译时计算的。此时 (:servername (req/ring-request)) 为 nil,因此“localhost”将被硬编码到为您的视图生成的类文件中。
  • 所以在 irc 上与某人交谈时,他们提到了使用 'at' 的可能性,但是,由于在每个请求上重新编译模板,存在一些性能考虑

标签: clojure enlive


【解决方案1】:

如 cmets 中所述,deftemplate 是一个宏,将模板定义为命名空间中的函数 - 仅在首次评估时进行一次。您可以轻松编写一些代码来懒惰地创建模板,并在创建模板后通过缓存模板来消除一些开销:

(def templates (atom {}))

(defmacro defservertemplate [name source args & forms]
  `(defn ~name [& args#]
     (let [src# (get-template ~source)]
       (dosync
        (if-let [template# (get templates src#)]
          (apply template# args#)
          (let [template# (template src# ~args ~@forms)]
            (swap! templates assoc src# template#)
            (apply template# args#)))))))

在你的情况下,你可以说(defservertemplate base "/base.html"...

您可以稍微整理一下。您真正需要知道的是deftemplate 只是调用template,如果您愿意,可以直接使用它。

【讨论】:

    猜你喜欢
    • 2020-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多