Protect_from_forgery & Unobtrusive Javascript

У меня есть javascript, создающий ajax-вызов на моем сайте Rails:

$.ajax({type: "PUT", url: url, data: { dummy: data }, complete: function(data) {}});

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

Может ли кто-нибудь помочь мне?

Ответ 1

В своем макете добавьте это перед любыми другими запусками JS:

<script>
  function authToken() {
    return '<%= form_authenticity_token if protect_against_forgery? -%>';
  }
</script>

authToken закодирован как функция, так что он менее вероятно, что вы случайно перезапишете его другим JavaScript.

В качестве альтернативы, начиная с Rails 3, токен auth внедряется как тег <meta>, который вы можете читать с помощью

<script>
  function authToken() {
    return $('meta[name="csrf-token"]').attr('content');
  }
</script>

В главном JS вы можете вызвать authToken(), и он вернет токен аутентификации в виде строки, которая будет включена в ваши вызовы Ajax. Например, используя jQuery:

$.ajax({
  type: 'PUT',
  url:  url,
  data: {
    foo: bar,
    authenticity_token: authToken()
  },
  complete: function(data) {}
});

Обратите внимание, что если вы используете встроенный помощник form_for Rails, он автоматически добавляет токен аутентификации в скрытый ввод. Если вы хотите отправить все данные формы, включая скрытый токен аутентификации, вы можете просто использовать:

var $form = $('form');
$.ajax({
  url:      $form.attr('action'),
  type:     $form.attr('method'),
              // "get" or "post"; overridden by Rails' hidden "_method"
              // input value, e.g., "put"
  data:     $form.serialize(),
              // Includes hidden "authenticity_token" and "_method" inputs
  complete: function(data) {}
});

Этот шаблон часто полезен, когда вы уже создали форму, которая работает без JS, и вы добавляете ненавязчивый слой JS, который просто отправляет данные формы через Ajax.

Ответ 2

Спасибо за вышеупомянутое решение.
Я использую некоторые стандартные формы на моем сайте, которые не используют rails form_tag, поэтому я просто добавил его как скрытый элемент формы.

<form action="...">
    <%= hidden_field_tag 'authenticity_token', form_authenticity_token if protect_against_forgery? %>
    ... rest of form...
</form>

Работает с удовольствием.