Rails' `link_to foo, bar, method: "delete" 有 Yesod 替代品吗?
Is there a Yesod alternative to the Rails' `link_to foo, bar, method: "delete"?
有没有一种简单的方法可以生成 link,它使用与 Yesod 中的 GET
不同的方法,例如 Rails 上的 Ruby,其中可以执行 link_to foo, bar, method: "post"
,这将通过 JavaScript?
提交 link
update: Ruby on Rails 所做的是生成一个 data-method
属性,然后由它自己的 JavaScript图书馆。我不一定要寻找完全相同的解决方案,而是寻找在 Yesod 中创建 POST
links 的现有机制。
Is there a simple way to generate a link that uses a different method than GET in Yesod
我不知道。
an existing mechanism for creating POST links in Yesod
要具体生成 POST
link,您可以渲染样式看起来像 link 的表单。您可以将其包装在 postLink :: Route -> Widget
帮助器中。
下面是 Rails 的大致实现。这涉及几个部分:生成 link,使用 Javascript 实现方法更改功能,以及后端用于 CSRF 保护的额外代码。这是 linking 方面:
linkToPost :: Route App -> [(Text,Text)] -> Text -> Widget
linkToPost = linkToMethod "POST"
linkToMethod :: Text -> Route App -> [(Text,Text)] -> Text -> Widget
linkToMethod method url attributes content =
toWidget [hamlet|
$newline never
<a href="@{url}" rel="nofollow" data-method="#{method}" *{attributes}>#{content}</a>
|]
你可以这样使用:
^{linkToPost CommentR [] "Create comment"}
此时需要Javascript来处理data-method
属性。您实际上可以只包含 rails.js
并且上面的代码可以正常工作。以给自己带来相当大的痛苦和许多运行时错误为代价,我提取了相关的 Javascript:
$(document).ready(function() {
$(document).on("click", "a[data-method]", function() {
var link = $(this);
var method = link.data('method');
handleMethod(link);
return false;
});
});
function handleMethod(link) {
var href = link.attr('href'),
method = link.data('method'),
csrfToken = $('meta[name=csrf-token]').attr('content'),
form = $('<form method="POST" action="' + href + '"></form>'),
metadataInput = '<input name="_method" value="' + method + '" type="hidden" />';
if (csrfToken !== undefined) {
metadataInput += '<input name="_token" value="' + csrfToken + '" type="hidden" />';
}
form.hide().append(metadataInput).appendTo('body');
form.submit();
}
注意,如果表单有POST类型的方法和_method
参数,Yesod默认middleware会覆盖方法为_method
的值,就像 Rails。上面的 Javascript 假设已启用。
为了利用 Rails.js 正在使用的 CSRF 保护,我们需要将 CSRF 令牌嵌入到我们页面的 <head>
中。首先,我在 defaultLayout
函数中获取 CSRF 令牌:
mCsrfToken <- fmap reqToken getRequest
然后嵌入到页面header里面default-layout-wrapper.hamlet
:
$maybe token <- mCsrfToken
<meta name="csrf-token" content=#{token}>
此时,可以应用用于表单的正常CSRF 保护。对我来说已经晚了,但我想出了这个作为简单请求(如 DELETE /users/1)检查 CSRF 令牌的方法,可能有比这更好的方法:
checkCsrf :: Handler ()
checkCsrf = do
((res, _), _) <- runFormPost (renderDivs (mempty :: AForm Handler () ))
case res of
FormSuccess _ -> return ()
_ -> permissionDenied "CSRF failure"
这是一个很长的答案 + 我有点累了,欢迎对上面的代码进行审查。
更新
现在 Yesod 支持 embedding CSRF tokens in cookies,并在请求 header 中验证它们,您可能想要使用它而不是将令牌嵌入 HTML 并制作您的申请表格。推理:
- 从 cookie 中查找值比 HTML 查询更简单且支持更好。
- 添加请求 header 与 POSTing JSON/binary 数据等兼容。对我来说,这似乎不那么 hacky。
- Yesod测试明确支持所有这些
有没有一种简单的方法可以生成 link,它使用与 Yesod 中的 GET
不同的方法,例如 Rails 上的 Ruby,其中可以执行 link_to foo, bar, method: "post"
,这将通过 JavaScript?
update: Ruby on Rails 所做的是生成一个 data-method
属性,然后由它自己的 JavaScript图书馆。我不一定要寻找完全相同的解决方案,而是寻找在 Yesod 中创建 POST
links 的现有机制。
Is there a simple way to generate a link that uses a different method than GET in Yesod
我不知道。
an existing mechanism for creating POST links in Yesod
要具体生成 POST
link,您可以渲染样式看起来像 link 的表单。您可以将其包装在 postLink :: Route -> Widget
帮助器中。
下面是 Rails 的大致实现。这涉及几个部分:生成 link,使用 Javascript 实现方法更改功能,以及后端用于 CSRF 保护的额外代码。这是 linking 方面:
linkToPost :: Route App -> [(Text,Text)] -> Text -> Widget
linkToPost = linkToMethod "POST"
linkToMethod :: Text -> Route App -> [(Text,Text)] -> Text -> Widget
linkToMethod method url attributes content =
toWidget [hamlet|
$newline never
<a href="@{url}" rel="nofollow" data-method="#{method}" *{attributes}>#{content}</a>
|]
你可以这样使用:
^{linkToPost CommentR [] "Create comment"}
此时需要Javascript来处理data-method
属性。您实际上可以只包含 rails.js
并且上面的代码可以正常工作。以给自己带来相当大的痛苦和许多运行时错误为代价,我提取了相关的 Javascript:
$(document).ready(function() {
$(document).on("click", "a[data-method]", function() {
var link = $(this);
var method = link.data('method');
handleMethod(link);
return false;
});
});
function handleMethod(link) {
var href = link.attr('href'),
method = link.data('method'),
csrfToken = $('meta[name=csrf-token]').attr('content'),
form = $('<form method="POST" action="' + href + '"></form>'),
metadataInput = '<input name="_method" value="' + method + '" type="hidden" />';
if (csrfToken !== undefined) {
metadataInput += '<input name="_token" value="' + csrfToken + '" type="hidden" />';
}
form.hide().append(metadataInput).appendTo('body');
form.submit();
}
注意,如果表单有POST类型的方法和_method
参数,Yesod默认middleware会覆盖方法为_method
的值,就像 Rails。上面的 Javascript 假设已启用。
为了利用 Rails.js 正在使用的 CSRF 保护,我们需要将 CSRF 令牌嵌入到我们页面的 <head>
中。首先,我在 defaultLayout
函数中获取 CSRF 令牌:
mCsrfToken <- fmap reqToken getRequest
然后嵌入到页面header里面default-layout-wrapper.hamlet
:
$maybe token <- mCsrfToken
<meta name="csrf-token" content=#{token}>
此时,可以应用用于表单的正常CSRF 保护。对我来说已经晚了,但我想出了这个作为简单请求(如 DELETE /users/1)检查 CSRF 令牌的方法,可能有比这更好的方法:
checkCsrf :: Handler ()
checkCsrf = do
((res, _), _) <- runFormPost (renderDivs (mempty :: AForm Handler () ))
case res of
FormSuccess _ -> return ()
_ -> permissionDenied "CSRF failure"
这是一个很长的答案 + 我有点累了,欢迎对上面的代码进行审查。
更新
现在 Yesod 支持 embedding CSRF tokens in cookies,并在请求 header 中验证它们,您可能想要使用它而不是将令牌嵌入 HTML 并制作您的申请表格。推理:
- 从 cookie 中查找值比 HTML 查询更简单且支持更好。
- 添加请求 header 与 POSTing JSON/binary 数据等兼容。对我来说,这似乎不那么 hacky。
- Yesod测试明确支持所有这些