【发布时间】:2014-01-26 13:31:02
【问题描述】:
我有相当深的带有 ID 的网址,我想看看我是否可以将它们转换成更好看的东西。我尝试研究如何为 Yesod 博客 (https://github.com/yesodweb/yesod/wiki/Slugs) 完成 Slugs,但不确定我是否知道如何将其翻译成我在这里寻找的内容。
假设我想显示热门小说书籍,我有一个如下所示的资源:
/topbooks/bookcategory/#BookCategoryId
如果我去/topbooks/bookcategory/1,我可能会得到小说类书籍,如果我去/topbooks/bookcategory/2,我可能会得到非小说类书籍等。
我的所有处理程序都在数据库查询中使用#BookCategoryId 输入参数来获取适当的记录。
理想情况下,我想创建一个如下所示的网址:/topbooks/fiction、/topbooks/non-fictionetc。如果我将路由创建为/topbooks/#Text,我可以对字符串进行模式匹配并返回Key。但是,我必须使用#BookCategoryId 在每个处理程序中手动转换它。请注意,ID 用作外键,因此依赖 getBy 有点麻烦,就像在 Slug 示例中所做的那样。
所以我想知道是否有更好的方法来做到这一点:是否可以定义一个类似于Slug 的自定义类型,但不仅仅是在文本/字符串之间转换值,而是实际输出IDs?这样我就可以直接在我的查询中使用该参数。
更新:
鉴于迈克尔的评论澄清:
我知道如果不进行数据库查找,我们将无法获取 ID。事实上,对于这个例子,我可以对查找机制进行硬编码。我只是想看看PathPiece 机制是否会以某种方式简化转换过程。
例如,如果这样的事情有效,那么它会很好,但我当然会得到一个类型错误,因为当编译器期望 BookCategories 时我试图返回一个 Key。
data BookCategories = FICTION | NONFICTION
instance PathPiece BookCategories where
toPathPiece (FICTION) = T.pack "fiction"
toPathPiece (NONFICTION) = T.pack "nonfiction"
fromPathPiece s =
let ups = map toUpper $ T.unpack s
in
case reads ups of
[(FICTION, "")] -> Just $ Key $ PersistInt64 1
[(NONFICTION, "")] -> Just $ Key $ PersistInt64
[] -> Nothing
otherwise -> Nothing
当然,我可以直接返回 Just FICTION 并在我的处理程序中打开它。这在概念上与直接使用带有签名Text -> BookCategoryId 的函数对 Text 进行实际模式匹配并没有太大区别。
getBookCategoryR :: BookCategoryId -> Handler Html
getBookCategoryR bcId = do
-- Normal use case when IDs are used in the URL
books <- runDB $ selectList [ModelBookCategory ==. bcId] []
如果我切换到文本输入
getBookCategoryR :: Text -> Handler Html
getBookCategoryR bc = do
bcId = convertToId (bc) -- This is the line I am trying to avoid everywhere
books <- runDB $ selectList [ModelBookCategory ==. bcId] []
单行转换代码是我试图避免的。 PathPiece 已经很好地处理了基于 id 的 URL 并保持代码干净。如果有办法通过一些 Type 魔法返回 Id,那就太好了。由于对 Haskell 的了解有限,我不知道它是否可行。
希望我的问题现在更清楚了。
谢谢!
【问题讨论】: