Ajax Forms с Rails 3 - лучшая практика? - PullRequest
22 голосов
/ 18 ноября 2011

То, что считается Rails Way для Ajax Forms

До сегодняшнего дня я думал, что я использую формы Rails + jQuery UJS был правильным способом сделать это, но обновление до jQuery 1.7 «сломало» путьЯ делал это до сих пор.

Как это сделать?

Я хочу использовать Ajax с моими формами.Ответ ajax должен либо снова отобразить форму (например, при возникновении ошибок), либо перенаправить на страницу успеха.(Возможно, он должен делать больше, например, показ мод, но я хочу, чтобы этот пример был простым).

1.Использование EJS и $ ('# formid'). Html (...)

Это то, что я делал до настоящего времени.Мой ajax-ответ был шаблоном ejs, который возвращал код javascript для повторного отображения формы (с ошибками) или в зависимости от того, была ли ошибка, перенаправил пользователя на страницу успеха:

<% unless @success_submit %>
$('#form_wrapper').html('<%= escape_javacsript( render :partial => 'form' ) %>'); 
<% else %>
document.location = '/success_thank_you';
<% endif %>

Теперь представьте, что форма содержит ошибкусообщение типа div

<div class="error_message">BlaBla</div>

Чтобы добавить приятный эффект, у меня было завершено общее событие jQuery.live, связанное с завершением ajax, которое выделило ошибки.

$('form').live('ajax:complete', function() {
   // do stuff like highlighting all error messages in that form
}); 

Это не работает с jQuery1.7+ jquery-ujs больше (вероятно, по уважительным причинам).Так что, думаю, то, как я это сделал, было неправильно.

2.Используя вышеприведенный способ, но повторяю себя

Вместо того, чтобы связывать событие ajax: complete, я мог бы делать "вещи с подсветкой ошибок" в EJS, например

$('#form_wrapper').html('<%= escape_javascript( render :partial => 'form' ) %>');
$('#form_wrapper form .error_message').fadeIn();

Но это означало бы, что мне придетсяПовторите вторую строку почти в каждом EJS, который отображает формы.И, конечно же, я хочу сохранить это СУХОЙ.

3.Ajax-ответ отображает чистый html, ajax: complete обрабатывает события display

Совершенно другое решение состоит в том, что ajax-ответ просто отображает чистый html, а мой пользовательский обработчик ajax: complete позаботится об отображении формы.Обработчик будет выглядеть так:

$('form').live('ajax:success', function(ev, data, status, xhr) {
  $(this).html(data);
  // and e.g. highlight stuff
  $(this).children('.error_message').fadeIn();
});

Это будет работать.Но теперь, что мне делать, если мой сервер решит не визуализировать форму снова (например, после успешной регистрации), а вместо этого перенаправить на другой URL или показать модальную форму.Сервер может ответить примерно так:

<script>
   document.location = '/success.blabla/';
</script>

Но разве это хорошее решение?

4.Пользовательский протокол JSON

Вероятно, хорошим решением было бы использовать версию 3, но вместо простой замены текущей формы возвращаемым html, мы могли бы создать некоторый пользовательский протокол json.Таким образом, мы могли бы даже позволить серверу отвечать такими вещами, как

  1. первый модальный показ (например, «Успешная регистрация»)
  2. перенаправление на страницу входа

Обработчик ajax: success может проверить, является ли ответ чистым html, в этом случае он заменит текущую форму html-кодом.Но если ответ представляет собой массив JSON, он будет обрабатывать это, например, сервер отвечает с

{ html: '<%= render :partial => 'something' %>', 
  show_modal:  '<%= render :partial => 'modal_template' %>',
  redirect_after_modal: '/login_page'
}

Обработчик ajax: success будет обрабатывать его как

$('form').live('ajax:success', function(ev, data, status, xhr) {
   // try parsing json
   if (data.json['show_modal') { // show modal code.... }; 
   if (data.json['redirect']) { document.location=data.json['redirect']);...
});

Как вы это делаетевещи

Очевидно, что есть много способов обработки форм Ajax.Но как ты это делаешь, и что считается наилучшей практикой с Rails?

Ответы [ 2 ]

8 голосов
/ 18 ноября 2011

Итак, я смог свести вашу проблему только к jquery, и, конечно же, она работает в jquery 1.6.4 , но не в jquery 1.7 .

Кажется, что если вы замените элемент в DOM, а затем активируете событие в объекте jquery, созданном из исходного элемента, 1.6.4 все равно вызовет событие в исходном местоположении элементов и позволит ему распространяться вверх по DOM. 1.7, однако, не сработает элемент (что имеет больше смысла).

Я только что провел поиск в журнале изменений jquery 1.7 и, конечно же, вот два билета, которые исправили это поведение: 9951 и 10489 .

Чтобы ответить на ваш вопрос о том, что является лучшей практикой для выполнения чего-то подобного, я бы сказал, взять под контроль, в каком порядке запускаются ваши события. jQuery автоматически выполняет JS, возвращенный в ответах ajax, что означает, что вы не можете контролировать, когда это произойдет.

Самый простой способ изменить код - это вернуть сам фрагмент HTML, а затем использовать jquery для замены формы на возвращенный HTML в обработчиках ajax:complete или ajax:success / ajax:error. Таким образом, вы можете быть уверены, что все происходит в том порядке, в каком вы хотите.

Чтобы увидеть, как именно это сделать, попробуйте прочитать [мои статьи]:

Или см. вики jquery-ujs для этих ссылок и т. Д.

0 голосов
/ 20 мая 2013

Не уверен, если вам это нужно больше, но вот что мы сделали для реализации форм с AJAX

Предположим, у нас есть действия, которые выглядят как

def new
  @saved_search = SavedSearch.new
new

def create
  if @saved_search.save
    respond_to do |format|
      format.js { render :saved }
    end
  else
    respond_to do |format|
      format.js { render :new }
    end
  end
end

, и у нас есть формаэто выглядит как

# app/views/saved_searches/new.html.erb
<%= form_for @saved_search,  url: saved_searches_path(format: :js), remote: true do |f| %>
  <div class="form">
    <div class="content">
      <div class="field">
        <%= f.label(:name, t(".name_search"), class: "label") %>
        <%= f.text_field(:name, size: "25", autofocus: "autofocus") %>
      </div>

      <div class="clear"></div>
    </div>

    <footer class="clear">
      <div class="left">
        <%= f.button t(".save"), class: "button" %>
      </div>
      <div class="clear"></div>
    </footer>
  </div>
<% end %>

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

# app/views/saved_searches/new.js.erb
<%- @saved_search.errors.keys.each do |field| %>
  $('#saved_search_<%= field %>').after("<span class=\"errors\">&nbsp;<%=   @saved_search.errors[field].join(',')  %></span>")
  $('#saved_search_<%= field %>').wrap('<div class="field_with_errors" />');;
<% end %>

, который не тормозит привязки JQuery или обратный вызов, но все же представляет вам ошибки.

Теперь я думаю, что было бы неплохо написать некоторыеконструктор форм, который сможет как визуализировать HTML-форму, так и возвращать кучу директив JQuery для полей формы, принимая во внимание

Rails.configuration.action_view.field_error_proc

...