Envíe el formulario en rieles 3 de forma ajax (con jQuery)

79

Soy un principiante en rieles y jQuery. Tengo dos formularios separados en una página y quiero enviarlos por separado en forma ajax (con jQuery). Hasta aquí llegué. ¿Alguien puede agregar o corregir este código para que funcione? Estoy usando Rails 3.1 y jQuery 1.6. Gracias de antemano.

application.js

$(".savebutton").click(function() { 
    $('form').submit(function() {
         $(this).serialize();
    });
}); 

primera forma:

<%=form_for :users do |f| %>
  <fieldset>
    <legend>Basic details</legend>
    <%= f.label :school %>
    <%= f.text_field :school,:size=>"45",:class=>"round",:id=>"school" %><br/>      
  </fieldset>
  <p><%= button_to "save and continue",{:class=>"savebutton"} %></p>
<%end%>

segunda forma:

<%=form_for :courses do |c| %>
  <fieldset>
    <legend>Your current classes</legend>
    <label>class:</label><%= c.text_field :subject,:size=>"45",:class=>"round" %><br/>
  </fieldset>
  <p><%= button_to "save and continue",{:class=>"savebutton"} %></p>
<%end%>

SchoolController

class SchoolController < ApplicationController
  respond_to :json
  def create
    @school = current_user.posts.build(params[:school].merge(:user => current_user))
    if @school.save
      respond_with @school
    else
      respond_with @school.errors, :status => :unprocessable_entity
    end
  end
end

CourseController tiene la misma forma que SchoolController

Katie
fuente

Respuestas:

108

Tú quieres:

  1. Detenga el comportamiento normal de someterse.
  2. Envíelo a través de ajax al servidor.
  3. Reciba una respuesta y cambie las cosas en consecuencia.

El siguiente código debería hacer eso:

$('form').submit(function() {  
    var valuesToSubmit = $(this).serialize();
    $.ajax({
        type: "POST",
        url: $(this).attr('action'), //sumbits it to the given url of the form
        data: valuesToSubmit,
        dataType: "JSON" // you want a difference between normal and ajax-calls, and json is standard
    }).success(function(json){
        console.log("success", json);
    });
    return false; // prevents normal behaviour
});
Johan
fuente
14
Esto no funcionó para mí en el formulario anterior. Creo que fue porque estaba intentando publicar en un recurso, que usa la misma URL para el índice y crea métodos en Rails, esto requiere forzar que la solicitud sea una POST. Si desea enviar una solicitud de formulario para algo que se ha declarado como recurso routes.rb, deberá asegurarse de que está utilizando un POST y no un GET. Usando jQuery, simplemente agregue type: 'POST'a la $.ajaxllamada.
Eli Hooten
Implementé este código, pero parece que no se envía realmente. Tengo que envolverlo en una $(CODE).submit();llamada para que se ejecute, luego envía 2 publicaciones. ¿Algunas ideas?
thinkpunch
¿Cómo hago esto si tengo un formulario bastante grande? .serialize () provocará un error de URI de solicitud demasiado largo al enviarlo.
zykadelic
Vea el primer comentario, luego debe hacer una solicitud POST. Así que agregue type: 'POST'a la llamada ajax.
Johan
1
Esta respuesta realmente no es el camino de los rieles.
Mild Fuzz
58

Si usa :remote => trueen sus formularios, puede enviarlos con JavaScript con

$('form#myForm').trigger('submit.rails');
Pelusa leve
fuente
4
Hoy me picó un error en mi código, así que publico para ayudar a otros que terminan en una situación como la mía. Tenía un campo oculto y, accidentalmente (error de copiar y pegar), tenía el campo marcado como "obligatorio". El campo no tenía un valor asignado (debería haber sido asignado estáticamente por mí). Dado que está oculto, no hay ningún artefacto de interfaz de usuario al que los rieles le indiquen para que lo arregle. Más bien, cuando se envía el formulario, los rieles activarán silenciosamente un evento al que si no se suscribe, no sabrá qué diablos está pasando y por qué nunca se envió el formulario.
sábado
1
Enviar un formulario de forma silenciosa a través de AJAX siempre tiene este problema en desarrollo. Debería haber podido ver que la transacción se produce en sus herramientas de desarrollo. Además, solo debe aplicar AJAX una vez que su formulario se envíe correctamente.
Fuzz leve
interesante, no sabía eso
Alain Goldman
Esta es la mejor respuesta con UJS. Supongamos que tiene un formulario que obtiene de forma asincrónica un token de Stripe de un servicio remoto al enviar el formulario. En su función de devolución de llamada de Stripe, obtiene la respuesta de Stripe y ahora debe enviar su formulario nuevamente a la acción de creación de Rails. Si lo hace usando .ajax, no podrá manejar los datos de éxito y error en su plantilla 'create.js.erb' como debería. Intente utilizarlo .submit()por segunda vez y remote => trueperderá su token de autenticación y. .triggerrocks, su formulario lo hará #create como debería, renderizando 'create.js.erb'
user3670743
@ user3670743 - gracias. ¿Puede desarrollar este punto?
BKSpurgeon
33

La forma preferida en Rails 3 de realizar el envío de formularios ajax es utilizar Rails-ujs.

Básicamente, permite que Rails-ujs haga el envío ajax por usted (y no necesitará escribir ningún código js). Luego, simplemente escribe código js para capturar el evento de respuesta (u otros eventos) y haz lo tuyo.

Aquí hay algunos códigos:

Primero, use la opción remota en form_for para que el formulario se envíe a través de ajax de forma predeterminada:

form_for :users, remote:true do |f|

Luego, cuando desee realizar alguna acción basada en el estado de respuesta de ajax (por ejemplo, respuesta exitosa), escriba la lógica de javscript así:

$('#your_form').on('ajax:success', function(event, data, status, xhr) {
  // Do your thing, data will be the response
});

Hay varios eventos a los que puede conectarse.

lulalala
fuente
1
Lo mismo en Rails 4, donde viene instalado en la plantilla de proyecto predeterminada. Y no olvide establecer el data: {type: 'text'}atributo como se documenta en api.jquery.com/jquery.ajax o la solicitud puede fallar debido a un error de análisis JSON.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
13

Para enviar el formulario a través de AJAX, simplemente puede pasar :remote => trueal form_forayudante. Por defecto, rails 3.0.x usa prototype js lib, pero puedes cambiarlo a jquery con la jquery-railsgema (que es el predeterminado para rails 3.1). bundle installit y luego rails g jquery:installreemplazar los archivos prototipo con jquery.

Después de eso, solo necesitará manejar la devolución de llamada. Echa un vistazo a este screencast

cuello bajo
fuente
ya tengo la biblioteca jquery en mi directorio y eliminé los archivos prototipo, jquery funciona pero solo necesito enviar el formulario desde allí
katie
El instalador ya no es necesario: stackoverflow.com/questions/7103437/…
Alex Moore-Niemi
2

es muy importante en su solicitud con ajax detener el comportamiento predeterminado, enviar remoto: verdadero en su formulario_para

<%= form_for :session, url: sessions_path, remote: true, html: { class: "form-signin" } do |f| %>

<% end %>

en tu ajax

$(".form-signin").on("submit", function(e) {
    $.ajax({
        url: $(this).attr('action'),
        data: $(this).serialize(),
        type: "POST",
        dataType: "json",
        success: function(response) {
            console.log(response)
        },
        error: function(xhr, textStatus, errorThrown) {}
    });
    e.preventDefault(); //THIS IS VERY IMPORTANT
});
Ezequiel García
fuente
0

Nada aquí funcionó para mí, mi problema era que la biblioteca modal jQuery evitaría que mis formularios se enviaran a través de datos remotos si mostraba una ventana modal, pero encontré una solución.

Primero agregue el complemento de formulario jQuery al directorio de JavaScript de sus activos: http://malsup.github.io/jquery.form.js

Ahora anule el método de envío de su formulario. Por ejemplo, podrías hacer algo como esto:

= form_for @object, html: {class: "ajax_form_submit"}, authorization_token: true do |f|
  = f.text_input

javascript:

  $(document).on('ready page:load', function() {

    $(".ajax_form_submit").submit(function () {
      var form = $(this)
      form.ajaxSubmit({
        success: function (responseText, statusText, xhr) {
          console.log('success: ajax_form_submit')
        },
        error: function (jqXHR, statusText, errorThrown) {
          console.log('error: ajax_form_submit');
          console.log(jqXHR, statusText, errorThrown);
        }
      })
    })

  })
Mike Bethany
fuente