我需要在页面上有一堆链接,每个链接都会向不同的控制器发出POST。但是当我使用普通链接时,我得到一个ActionController :: InvalidAuthenticityToken错误。我理解这是因为缺少authenticity_token值。但我不想使用表单来进行POST,因为我希望它们是链接而不是按钮。事实是,我想完全控制链接和按钮的样式,只是不要为我做。做这些事情的标准方法是什么?
答案 0 :(得分:2)
你有很多选择。
protect_from_forgery :only => []
答案 1 :(得分:1)
从技术上讲,你应该使用按钮和表单来处理非GET
的任何内容;超链接故意不允许GET
以外的方法(没有像_method
参数那样的黑客攻击)。一个非常实际的原因是,有时候,“网页加速器”浏览器附加组件会在页面中预取链接;如果GET链接启动了一个变异动作,则可能会错误地修改用户或资源状态。
也就是说,你可以将按钮设置为像链接一样;我使用类似下面的东西来做得很好。它假定一个适当的CSS重置,边距和填充以及所有好东西被填充。
input.restlink {
border: 0;
background: #fff;
color: #236cb0;
cursor: pointer;
}
input.restlink:hover {
text-decoration: underline;
}
使用这样的规则,您可以使用<%=button_to "Yay button", something_path, :method => :post %>
,它看起来和行为就像一个链接就好了。
答案 2 :(得分:1)
如果你使用的是jQuery,你也可以这样做:
<!-- in your view -->
<%= form_tag( user_free_dates_path(:user_id => @user.id), :remote => true ) do |f| %>
<%= hidden_field_tag :date, current_day.to_s(:short_db) %>
<%= link_to "Allow", "#", :class => "submit"%>
<% end %>
// in application.js
$("form a.submit").live("click", function(){
$(this).closest("form").submit();
return false;
});
您的想法是在视图中构建“真实”表单,而无需提交按钮。然后,带有“submit”类的link_to将触发表单提交。最终结果看起来像一个链接,但实际上它是一个表单。我确信使用Prototype有类似的方式。
在我的示例中, user_free_dates_path(:user_id =&gt; @ user.id)只是路径助手,而 hidden_field_tag 是我参与的参数之一传递我的POST请求。
答案 3 :(得分:0)
如果你不反对使用jQuery和一些ajax'n,我有一个blog post来涵盖这个。
如果您想要高级概述,请参阅以下基本信息。
添加你的布局:
<%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %>
此代码将auth令牌添加到响应中。通过这种方式,JS可以将其提取并提交给服务器。
接下来,我们拦截application.js中的任何ajax调用:
function isPost(requestType) {
return requestType.toLowerCase() == 'post';
}
$(document).ajaxSend(function(event, xhr, settings) {
if (isPost(settings.type)) {
settings.data = (settings.data ? settings.data + "&" : "") + "authenticity_token=" + encodeURIComponent( AUTH_TOKEN );
}
xhr.setRequestHeader("Accept", "text/javascript, application/javascript");
});
将此添加到您的应用程序控制器:
before_filter :correct_safari_and_ie_accept_headers
after_filter :set_xhr_flash
protected
def set_xhr_flash
flash.discard if request.xhr?
end
def correct_safari_and_ie_accept_headers
ajax_request_types = ['text/javascript', 'application/json', 'text/xml']
request.accepts.sort!{ |x, y| ajax_request_types.include?(y.to_s) ? 1 : -1 } if request.xhr?
end
在你看来:
<%= link_to "Delete", delete_product_path(product), :class => 'delete' %>
返回application.js:
$('a.delete').live('click', function(event) {
if(event.button != 0) { return true; }
$.post(link.attr('href').substring(0, link.attr('href').indexOf('/delete')), { _method: "delete" });
return false;
});
此示例执行删除操作,但处理帖子或放置的过程确实相同。博客文章有一个完整的示例应用程序来演示这一点。
答案 4 :(得分:0)
大量借用这些答案/来源
获取一个看起来像链接但功能类似按钮的按钮。在我的app / helpers / application_helper.rb中:
def button_as_link(action, link_text, hiddens)
capture do
form_tag(action, :class => 'button_as_link') do
hiddens.each { |k, v| concat hidden_field_tag(k.to_sym, v) }
concat submit_tag(link_text)
end
end
end
CSS:
form.button_as_link {
display: inline;
}
/* See https://stackoverflow.com/a/12642009/326979 */
form.button_as_link input[type="submit"], form.button_as_link input[type="submit"]:focus, form.button_as_link input[type="submit"]:active {
/* Remove all decorations to look like normal text */
background: none;
border: none;
display: inline;
font: inherit;
margin: 0;
padding: 0;
outline: none;
outline-offset: 0;
/* Additional styles to look like a link */
color: blue;
cursor: pointer;
text-decoration: underline;
}
/* Remove extra space inside buttons in Firefox */
form.button_as_link input[type="submit"]::-moz-focus-inner {
border: none;
padding: 0;
}
最后在我的模板中,我调用了button_as_link函数:
button_as_link('/some/path',{:key1=>:val1,:key2=>:val2}, 'text to display')