Cайт веб-разработчика, программиста Ruby on Rails ESV Corp. Екатеринбург, Москва, Санкт-Петербург, Новосибирск, Первоуральск

Обработка AJAX-запросов в Ruby on Rails

Обработка AJAX-запросов в Ruby on Rails, рассмотрен обычный механизм, без использования возможностей Rails для обработки ajax-запросов. Те, кто достаточно хорошо знаком с построением таких приложений, пожалуй вряд ли найдет для себя что-то новое.

Для примера сделаем форму, которую будем отправлять через ajax.

1. Прописываем маршруты:

  get 'form' => 'forms#index', :as => :form
  post 'form' => 'forms#form_send', :as => :form_send

2. Контроллер:

class FormsController < ApplicationController

  # не использовать layout, кроме основной страницы, отображаемой через экшн index
  layout false, :except => :index

  # здесь отображаем форму
  # сюда приходят запросы 'GET' /form
  def index
    @name = nil
  end

  # здесь принимаем запрос на отправку формы
  # сюда приходят запросы 'POST' /form
  def form_send

    # для пущей безопасности проверим корректность запроса
    # принимаем только ajax-запросы
    unless request.xhr?
      head :bad_request
      return
    end

    # при повторном отображении формы,
    # значение, введенное пользователем сохранится
    @name = params[:name]

    # какие-то действия с данными формы, проверки
    ...

    # возможно отобразить ту же форму - используем _form.html.erb,
    # т.к. на странице изменился только этот блок, например,
    # в случае ошибки, но с выводом сообщения об ошибке
    if error
      render :partial => 'forms/form', locals: { error_message: 'Сообщение об ошибке' }
      return
    end

    # ...либо просто отобразить какой-то текст
    render :text => 'Форма успешно отправлена'

  end

end

3. Шаблон страницы, содержащей форму (views/forms/index.html.erb):

<%=

  # div.form_block - для загрузки результата выполнения ajax-запроса
  content_tag(:div, :class => :class => :form_block) do
    render 'form'
  end

%>

в том же файле прописываем код jQuery:

<script type="text/javascript" language="javascript">

  $(document).ready(function() {

    // блок, содержащий форму
    // в index.html.erb: 
    // content_tag(:div, :class => :class => :form_block)
    var form_block = $('div.form_block');
  
    // ловим отправку формы
    // в _form.html.erb:
    // form_tag(form_send_path, :id => :form_id)
    form_block.on('submit', 'form#form_id', function(e) {
  
      e.preventDefault();
  
      // собственно сам ajax-запрос
      // все данные берем из формы - url, данные
      $.ajax($(this).attr('action'), {
  
        async: false,
        cache: false,
        data: $(this).serialize(),
        dataType: 'html',
        type: 'POST',
  
        success: function (data, textStatus, jqXHR) {
          // результат записываем в блок формы
          form_block.html(data);
        },
  
        error: function () {
          alert('Ошибка запроса');
        }
      });
  
      return false;
  
    });

  });

</script>

4. Блок (партиал) формы (views/forms/_form.html.erb) - блок, который отрисовывается и в index, и можем вернуть как результат запроса, чтобы заново отобразить форму:

<%= 
  # отображение сообщение об ошибке, если есть
  if (error_message ||= nil)
    content_tag(:span, error_message, :class => :error_message)
  end
%> 

<%=
  form_tag(form_send_path, :id => :form_id) do
    label_tag(:name, 'имя') +
    text_field_tag(:name, @name) +
    submit_tag('отправить')
  end
%>

Единственное, что через такую форма нельзя отправить файлы на сервер, но для этого есть достаточно надежный механизм использования скрытого iframe.

Для простоты и чистоты кода опущены различные проверки. Про особенности использования layout при обработке исключений ajax-запросов я уже писал.

Механизм обработки ajax-запросов, предлагаемый в Ruby on Rails

Для использования механизмов ajax Ruby on Rails необходимо использовать :remote => :true (в кнопках, ссылках) для отправки ajax-запрса, а в контроллере:

respond_to
  format.js { render json: ... }
  ...

...и использовать уже блок (партиал) _form.js.erb:

$('#id').html("<%= render 'partial_name' %>");

Но с данным механизмом RoR я пока особо не разбирался, т.к. вышеописанный самописанный мной алгоритм меня устраивает полностью.