Подтвердить что ты не робот

Ajax Forms с Rails 3 - лучшая практика?

Что считается Rails Way для форм Ajax

До сегодняшнего дня я думал, что я использую 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: полное отображение дескрипторов событий

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

$('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-протокол. Таким образом, мы могли бы даже позволить серверу ответить такими вещами, как

  • первый показ модального (например, "Успех регистрации" )
  • перенаправление на страницу входа

Обработчик 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?

4b9b3361

Ответ 1

Итак, я смог довести вашу проблему до 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 wiki для этих ссылок и т.д.

Ответ 2

Не уверен, что вам это нужно больше, но вот что мы сделали для реализации форм с 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

в consideartion