true simple remote rails form_tag form example and ruby-on-rails ajax forms unobtrusive-javascript

ruby-on-rails - simple - ruby on rails ajax example



Ajax Forms with Rails 3-Best Practice? (2)

Lo que se considera el Camino Rails para Formas Ajax

Hasta hoy pensé que la forma en que utilizo los formularios de Rails + jQuery UJS era la forma correcta de hacerlo, pero la actualización a jQuery 1.7 "fracasó" en la forma en que lo hice hasta ahora.

¿Como hacer esto?

Quiero usar Ajax con mis formularios. La respuesta ajax debe representar el formulario nuevamente (por ejemplo, cuando se producen errores) o redirigir a una página exitosa. (Tal vez debería hacer más, como mostrar modales, pero quiero mantener este ejemplo simple).

1. Usando EJS y $ (''# formid''). Html (...)

Eso es lo que hice hasta la fecha. Mi respuesta ajax fue una plantilla de ejs que devolvió el código javascript para volver a generar el formulario (con errores) o, dependiendo de si fue un error, se redirigió al usuario a la página de éxito:

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

Ahora imagine que el formulario contiene un mensaje de error div como

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

Para agregar un buen efecto tuve un evento jQuery.live general vinculado a ajax complete que resaltaba los errores.

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

Eso ya no funciona con jQuery1.7 + jquery-ujs (probablemente por buenas razones). Así que supongo que la forma en que lo hice no estaba bien.

2. Usando el método anterior pero repito

En lugar de enlazar el evento ajax: complete, podría hacer el "error resaltando cosas" en el EJS como

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

Pero eso significaría que tendría que repetir la segunda línea en casi cada EJS que representa formularios. Y por supuesto quiero mantenerlo seco.

3. La respuesta de Ajax muestra html puro, ajax: se muestran los controladores de eventos completos

Una solución completamente diferente sería que la respuesta ajax simplemente mostraría html puro y mi controlador personalizado ajax: complete se encargaría de mostrar el formulario. El manejador se vería como

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

Eso funcionaria. Pero ahora, ¿qué debo hacer si mi servidor decide no presentar el formulario nuevamente (p. Ej., Después de un registro exitoso) pero en cambio redirige a otra URL o muestra un formulario modal? El servidor podría responder con algo así.

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

¿Pero es esa una buena solución?

4. Protocolo JSON personalizado

Probablemente, una buena solución sería utilizar la versión 3, pero en lugar de simplemente reemplazar el formulario actual con el HTML devuelto, podríamos crear un protocolo json personalizado. De esa manera, incluso podríamos dejar que el servidor responda con cosas como

  1. primer espectáculo modal (como ''Registro de éxito'')
  2. redirigir a la página de inicio de sesión

El controlador ajax: success podría verificar si la respuesta es simplemente html, en ese caso reemplazaría el formulario actual con el código html. Pero si la respuesta es una matriz JSON, lo manejaría, por ejemplo, el servidor responde con

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

El manejador de éxito ajax: habría manejado como

$(''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'']);... });

Como estas haciendo estas cosas

Obviamente, hay muchas maneras de cómo manejar los formularios ajax. Pero, ¿cómo lo está haciendo y qué se considera la mejor práctica con Rails?


No estoy seguro si lo necesita más, pero aquí es lo que hemos hecho para implementar formularios con AJAX

Supongamos que tenemos una acción que parece

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

y tenemos una forma que parece

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

Y, obviamente, queremos devolver un error si algunos campos no son válidos. Así que aquí hay un truco

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

Eso no frena los enlaces de JQuery ni la devolución de llamada, pero aún presenta errores.

Ahora estoy pensando que podría ser una buena idea escribir un creador de formularios, que sea capaz de representar un formulario HTML y devolver un montón de directivas JQuery para los campos de formulario, tomando

Rails.configuration.action_view.field_error_proc

en consideración


Por lo tanto, pude resumir su problema solo a jQuery, y por supuesto, funciona en jquery 1.6.4 , pero no en jQuery 1.7 .

Parece que si reemplaza un elemento en el DOM y luego desencadena un evento en el objeto jquery creado a partir del elemento original, 1.6.4 todavía activará el evento en la ubicación original de los elementos y le permitirá propagar el DOM. 1.7, sin embargo, no activará el elemento (lo que tiene más sentido).

Acabo de hacer una búsqueda en el registro de cambios de jquery 1.7 y, 9951 , aquí están los dos tickets que rectificaron este comportamiento: 9951 y 9951 .

Para responder a tu pregunta sobre cuál es la mejor práctica para lograr algo como esto, diría, toma el control sobre el orden en que se activan tus eventos. jQuery ejecuta automáticamente JS devuelto en las respuestas ajax, lo que significa que no tienes control sobre cuándo sucede eso.

La forma más fácil de modificar su código sería devolver el HTML parcial y luego usar jquery para reemplazar el formulario con el HTML devuelto en los manejadores de ajax:error ajax:complete o ajax:success / ajax:error . De esta manera, puede estar seguro de que las cosas suceden en el orden exacto que desea.

Para ver exactamente cómo lograr esto, intente leer [mis artículos]:

O vea el wiki de jquery-ujs para estos enlaces y más.