2012-04-07 23 views
19

Esta podría ser una de las preguntas más difíciles que he hecho, pero he estado estancado durante unos días, y pensé que sería mejor obtener el apoyo del comunidad más experimentada de carriles.Formulario AJAX (utilizando simple_form) con preservación de validación de error

Estoy trabajando en una aplicación ficticia que sigue esta guía más o menos ... ajax/jquery tutorial ...

Hacer mis propias personalizaciones, el guía me ayudó a crear una "marca" (incluye "modelo" modelos anidados, "submodelo" y "estilo") formulario de envío (usando simple_form) y listado de marcas en la misma página. Esto funciona perfectamente, y la validación (para mis modelos) se aplica. Sin embargo, cuando puse el formulario y el listado de marcas en la misma página, pierdo los claros errores de validación en línea que aparecían en la falla de envío (ver imagen a continuación). Al no ser capaz de obtener los errores de línea de trabajo ha hecho darme cuenta de que tengo más para aprender acerca de la representación .. y es por eso que estoy obsesionado con encontrar la respuesta a esta pregunta

enter image description here

... y aquí está la lista:

enter image description here

a continuación se muestra el controlador de la acción index:

def index 

    #This is for the product listing 

    @brands = Brand.all.reverse 

    #This is for the form 

    @brand = Brand.new 
    @model = Model.new 
    @submodel = Submodel.new 
    @style = Style.new 

    respond_to do |format| 
     format.html 
    end 
    end 

El formulario anterior crea la marca, modelo, submodelo, y el estilo para su uso en el formulario de presentación anidado ... A continuación se muestra el código para el formulario:

<%= simple_form_for @brand, :html => { :class => 'form-horizontal' }, :remote => true do |m| %> 

    <fieldset style = "margin-top:34px;"> 
    <legend></legend> 
    <%= m.input :name, :label => 'Brand' %>   
    <%= m.simple_fields_for :models, @model do |p| %>  
     <%= p.input :name, :label => 'Model' %> 
     <%= p.simple_fields_for :submodels, @submodel do |s| %> 
     <%= s.input :name, :label => 'Submodel' %> 
     <%= s.simple_fields_for :styles, @style do |ss| %> 
      <%= ss.input :name, :label => 'Style' %> 
     <% end %> 
     <% end %> 
    <% end %> 

    <div class="form-actions"> 
     <%= m.submit nil, :class => 'btn btn-primary' %> 
     <%= link_to 'Cancel', brands_path, :class => 'btn' %> 
    </div> 
    </fieldset> 
<% end %> 

Ahora bien, como se puede ver que estoy usando :remote => true .. Me gustaría que el formulario cree la nueva "marca" o que se vuelva a cargar con errores de validación en línea. Por el momento mis crear la acción se ve así:

def create 
    @brand = Brand.new(params[:brand]) 

    respond_to do |format| 
     if @brand.save 
     format.html { redirect_to brands_url, notice: 'Brand was successfully created.' } 
     format.json { render json: @brand, status: :created, location: @brand } 
     format.js 
     else 
     format.html { render action: "index" } 
     format.json { render json: @brand.errors, status: :unprocessable_entity } 
     format.js { render 'reload' } 
     end 
    end 
    end 

El código que aparece debajo de if @brand.save parece funcionar .. pero el código de abajo "si no" no funciona de la manera que me gustaría. Entonces, ¿qué está pasando cuando @brand NO guarda? Creo que el código dentro de la acción del índice se está ejecutando, entonces @ brand.errors se convierte en json (que supongo que es para los errores de validación de simple_form) y luego reload.js.erb se está ejecutando ..

En un intento de volver a cargar el formulario (con errores de validación) he puesto la línea $("#entryform").load(location.href+" #entryform>*",""); en reload.js.erb ... Cuando pongo datos no válidos en mi formulario reload.js.erb se llama, pero todo lo que sucede es que los campos de formulario vuelven a cargar en blanco, en lugar de tener los datos ingresados ​​y los errores de validación en línea.

Espero haber proporcionado suficiente información aquí para obtener ayuda .. Realmente estoy luchando en esta. ¡Gracias!

+0

Esto es * tan * cerca de lo que estoy tratando de hacer pero no lo estoy haciendo funcionar. Lamentablemente, la guía vinculada a la pregunta original se ha ido. Al llamar a 'simple_form_for', no establece' "data-type" =>: json'? En el controlador, ¿tiene que llamar a ambos 'format.json' * y *' format.js'? Y en el JavaScript, no tiene que devolver '@ brand.errors' como una variable local. Tal vez es diferente porque estoy usando un modal. Empecé una nueva pregunta con la esperanza de obtener una aclaración: [Mostrar errores en línea con simple_form en un Bootstrap Ajax modal] (http://stackoverflow.com/q/13408508/550712) –

Respuesta

30

Creo que se puede simplificar esta poniendo su forma en un parcial (lo llamaremos simple_form), y poner este código en reload.js.erb:

$("#entryform").html("<%= escape_javascript(render :partial => 'simple_form') %>"); 

No estoy familiarizado con el método de jQuery load, pero supongo que hace una segunda solicitud. La clave con errores de representación es la variable de instancia (@brand) que está utilizando mientras renderiza el formulario tiene que ser el mismo que intentó guardar en crear, por lo que puede verificar los errores en él. Esta es la razón por la que siempre usa render en lugar de redirect_to cuando quiere presentar errores.Si realiza una redirección, inicia una nueva solicitud, lo que significa que @brand se reinicializa. Supongo que su $(...).load(...) está teniendo el mismo problema.

+2

No solo respondió mi pregunta (con un solución de trabajo simple) ... usted proporcionó una gran explicación también. Estupendo. – Abram

+0

Puede haber un problema con este método, si tiene un javascript adjunto a cualquiera de los elementos dentro del formulario, no funcionará después de que se represente el formulario con los errores – JustMichael

+1

@JustMichael en este caso adjuntar controladores de eventos a elementos principales, por ejemplo en lugar de '$ ('# target'). on ('click', function (e) {...})' use '$ (document) .on ('click', '#target', function (e) {...}) ' – Kote

0

Compruebe esto: al llamar .html (...) se duplicará el div del contenedor. Utilice .replateWith (...) en su lugar =]

1

Gracias por todos los Q & A de este. Me salvó.

Simplificando la estructura de archivos de @ tsherif una muesca (suponiendo que ya tenga un archivo js), resolví este problema al invocar el renderizado directamente en el formulario y mostrándolo a través de javascript/coffeescript.

#immediate_controller 
def action_with_modal 
    @brand = params[:failed_brand] || Brand.new 
end 

#brands_controller 
def create 
    @brand = Brand.new(params[:brand]) 

    respond_to do |format| 
    if @brand.save 
     ... 
    else 
     params[:failed_brand] = @brand 
     ... 
     format.js { render 'simple_form' } 
    end 
    end 
end 

#coffeescript 
$('form-selectors-here').on 'ajax:error', @reRegister 

reRegister: (e, data) => 
    $("div-that-contains-form").html(data.responseText) 
Cuestiones relacionadas