создание запроса POST в rails с гиперссылками

Мне нужна куча ссылок на странице, каждая из которых делает сообщение другому контроллеру. Но когда я использую обычные ссылки, я получаю ошибку ActionController::InvalidAuthenticityToken. Я понимаю, что это из-за недостающего значения authenticity_token. Но я не хочу использовать формы для публикации, потому что я хочу, чтобы они были ссылками, а не кнопками. Дело в том, что я хочу полный контроль над стилем ссылок и кнопок, просто не делайте этого за меня. Какой способ ведения таких вещи?

5 ответов


у вас есть много вариантов.

  1. отключить при регистрации: protect_from_forgery :only => []
  2. назначьте обработчику onclick ссылку и отправьте скрытую форму с помощью javascript.
  3. захватить во время создания представления и добавить его в качестве параметра запроса.

кстати, как именно вы делаете запросы "post", используя только атрибут "href"? Я думал, для этого нужна форма.


Технически говоря, вы должны использовать кнопки и формы для всего, что не является GET; гиперссылки намеренно не допускают методов GET (без хаков вроде


Если вы используете 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;
}); 

идея заключается в том, что вы создаете "реальную" форму в своем представлении без кнопки отправки. Затем link_to с классом "submit"запустит форму отправки. Конечный результат выглядит как ссылка, но на самом деле это форма. Я уверен, что есть аналогичный способ использования Prototype.

в моем примере user_free_dates_path (: user_id => @user.id) это просто помощник пути, и hidden_field_tag является одним из параметров, которые я передаю в своем запросе POST.


если вы не против использования jQuery и некоторых ajax'N, у меня есть блоге что это покрывает.

вот некоторые основные сведения, если вы хотите обзор высокого уровня.

добавьте этот ваш макет:

<%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %>

этот код добавляет маркер auth в ответ. Таким образом, JS может забрать его и отправить на сервер.

Далее мы перехватываем любой вызов ajax в приложении.js:

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' %>

вернуться к применению.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;
});

в этом примере выполняется удаление, но это действительно тот же процесс для обработки сообщений или puts. Сообщение в блоге имеет полный пример приложения, которое демонстрирует это.


заимствования в значительной степени из этих ответов / источников

получить кнопку, которая выглядит как ссылка, но работает как кнопка. В моем app / помощники / 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')