Validación de Rails sobre redirigir

Estoy probando el foro bestia escrito en Rails y usaré esto como un ejemplo de un problema que sigo enfrentando.

El foro tiene una acción de temas / presentación y una vista con un formulario en la parte inferior para crear una nueva publicación dentro del tema.

El envío del formulario va a publicaciones / crear y si la validación pasa redirige a temas / muestra y funciona bien; sin embargo, si la validación falla (dejando fuera el campo del cuerpo) se le redirige a los mismos temas / progtwig y vuelve al formulario , sin errores de validación … normalmente si la validación falla, queda en lo que sea / create con render: acción => nuevo.

¿Las validaciones se pierden en la redirección y cuál es el mejor método para hacerlo funcionar?

Vea el código a continuación:

PostsController.rb

def create @post = current_user.reply @topic, params[:post][:body] respond_to do |format| if @post.new_record? format.html { redirect_to forum_topic_path(@forum, @topic) } format.xml { render :xml => @post.errors, :status => :unprocessable_entity } else flash[:notice] = 'Post was successfully created.' format.html { redirect_to(forum_topic_post_path(@forum, @topic, @post, :anchor => dom_id(@post))) } format.xml { render :xml => @post, :status => :created, :location => forum_topic_post_url(@forum, @topic, @post) } end end end 

TopicsController.rb

  def show respond_to do |format| format.html do if logged_in? current_user.seen! (session[:topics] ||= {})[@topic.id] = Time.now.utc end @topic.hit! unless logged_in? && @topic.user_id == current_user.id @posts = @topic.posts.paginate :page => current_page @post = Post.new end format.xml { render :xml => @topic } end end 

temas / mostrar vista

   forum_topic_posts_path(@forum, @topic, :page => @topic.last_page) do |f| %>  
8 %> "posts/formatting" %>
'Save reply') %>

Muchas gracias.

Creo que tienes dos problemas aquí.

  1. Manteniendo los errores de validación a través de una redirección
  2. Repoblando los campos del formulario para que el usuario no tenga que volver a ingresar toda la información.

Ambas cosas están conectadas.

Los errores de validación generalmente se muestran a través del método error_msg_for que actúa sobre un objeto. Por lo general, el controlador lo proporciona como una variable de instancia de un objeto que no se pudo guardar. Esa misma variable de instancia se usa para volver a llenar el formulario.

Durante una redirección, el controlador generalmente creará una instancia de una variable de instancia utilizando hash de params. Por lo tanto, cualquier información utilizada para determinar por qué se perdió un error de guardado. Los recursos normales se mostrarán en caso de error de guardado y se redirigirá en caso de éxito, esto provoca que ocurran dos cosas.

  1. La instancia del objeto se pasa a error_msg_para crear ese bonito cuadro de error uniforme.
  2. La instancia del objeto se utiliza para rellenar los campos del formulario, lo que le permite a su usuario editar solo lo que sea necesario.

No conozco a Bestia tan bien, así que no estoy seguro de si el formulario para crear subprocesos es un modelo de registro activo. Pero lo siguiente le dará una idea de cómo solucionar su problema. Implicaría modificar tu copia local del complemento Beast, por lo que si estás utilizando una herramienta para mantenerla actualizada, es posible que pierdas los cambios.

He estado usando estos métodos para obtener sus problemas de validación. Suponiendo que el formulario del que se trata está basado en un nmodel, deberían proporcionarle todo lo que necesita para volver a llenar un formulario.

Básicamente, almacena una copia superficial del objeto con los errores en el hash flash, usando clone_with_errors. Debe usar una copia superficial o de lo contrario se encontrará con problemas cuando muestre errores para registros con múltiples asociaciones.

Luego uso my_error_msg_for, que toma las mismas opciones que el error_msg_for estándar para generar los mensajes de error html. Solo lo escribí porque, por alguna razón, el método estándar error_msg_for no funcionaba con los objetos almacenados en el hash. Es casi idéntico a la versión fuente oficial de error_msg_for que fue problemático.

/app/controllers/examples_controller.rb

 class ExamplesController < ApplicationController def update ... if @example.save regular action else flash[:errors] = clone_with_errors(@example) respond_to do |format| format.html redirect_to(@example) end end end 

/app/views/examples/show.html.erb

 
< % if flash[:errors] && !flash[:errors].empty? then -%>

< %= my_error_msg_for flash[:errors] %>

< % end -%>
...

Aquí está el código que necesita para que todo funcione.

application_controller.rb

  def clone_with_errors(object) clone = object.clone object.errors.each{|field,msg| clone.errors.add_to_base(msg)} return clone end 

application_helper.rb

  def _error_msg(*params) options = params.extract_options!.symbolize_keys if object = options.delete(:object) objects = [object].flatten else objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact end count = objects.inject(0) {|sum, this| sum + this.errors.count } unless count.zero? html = {} [:id, :class].each do |key| if options.include?(key) value = options[key] html[key] = value unless value.blank? else html[key] = 'errorExplanation' end end options[:object_name] ||= params.first options[:header_message] = "#{pluralize(count, 'error')} prohibited this #{options[:object_name].to_s.gsub('_', ' ')} from being saved" unless options.include?(:header_message) && !options[:header_messag].nil? options[:message] ||= 'There were problems with the following fields:' unless options.include?(:message) && !options[:message].nil? error_messages = objects.sum {|this| this.errors.full_messages.map {|msg| content_tag(:li, msg) } }.join contents = '' contents < < content_tag(options[:header_tag] || :h2, options[:header_message]) unless options[:header_message].blank? contents << content_tag(:p, options[:message]) unless options[:message].blank? contents << content_tag(:ul, error_messages) content_tag(:div, contents, html) else '' end end def my_error_msg_for(params) _error_msg_test :object_name => params[:object].class.name.gsub(/([az])([AZ])/,'\1 \2').gsub(/_/, " "), :object => params[:object], :header_message => params[:header_message], :message => params[:message] end 

Me temo que no sé nada de Bestia, pero hablando genéricamente, todo se pierde cuando redirige. Es una nueva solicitud de página, y todo se restablece a menos que se haya almacenado en algún lugar (la base de datos o la sesión, normalmente).

El flujo normal que tiende a ver con los formularios es redirigir si el objeto se guarda, pero se procesa si el guardado falla. El archivo de vista puede recoger las variables que se hayan establecido en el controlador, que normalmente incluirían el objeto que no guardó y sus mensajes de validación.

Lo siento, eso no resuelve tu problema, pero espero que pueda darte algunas pistas.

Mi respuesta a una pregunta muy similar publicada más recientemente aquí en StackOverflow cubre una serie de ventajas y desventajas para el debate redirect_to vs. render . Me encantaría saber si alguien tiene otros pros / contras para agregar a la discusión.