2011-03-18 21 views
17

Digamos que estoy creando un nuevo Foo mediante un formulario y un controlador de descanso rieles estándar, que es como la siguiente:Rieles: URL después de la validación falla al crear nuevos registros a través del formulario

class FoosController < ApplicationController 
    ... 
    def index 
    @foos = Foo.all 
    end 

    def new 
    @foo = Foo.new 
    end 

    def create 
    @foo = Foo.create(params[:foo]) 
    if @foo.save 
     redirect_to foos_path, :notice => 'Created a foo.' 
    else 
     render 'new' 
    end 
    end 
    ... 
end 

Por lo tanto, si use el controlador restful estándar (como arriba), luego cuando estoy creando el Foo estoy en el example.com/foos/new, y si envío el formulario y lo guardo correctamente estoy en example.com/foos mostrando la acción del índice. Sin embargo, si el formulario no se completa correctamente, el formulario se representa nuevamente y se muestran los mensajes de error. Esto es todo simple vainilla.

Sin embargo, si se muestran errores, se mostrará la página del formulario pero la URL será example.com/foos, porque la acción CREAR se publica en esa url. Sin embargo, uno esperaría encontrar el índice Foos # en example.com/foos, no el formulario que acaban de enviar ahora con los mensajes de error añadidos.

Este parece ser el comportamiento estándar de Rails, pero no tiene mucho sentido para mí. Obviamente, podría volver a redirigir a nuevo en lugar de renderizar nuevo desde la acción de creación, pero el problema es que los mensajes de error, etc. se perderían junto con los Foos parcialmente completos en la memoria.

¿Existe una solución limpia para este problema, una forma de enviar personas de nuevo a example.com/foos/new cuando hay errores en el nuevo formulario Foo que enviaron?

Gracias!

Respuesta

4

Se podría enganchar en los carriles de enrutamiento mediante la adición de esto en un inicializador: https://gist.github.com/903411

A continuación, sólo hay que poner los recursos ordinarios en su routes.rb:

resources :users 

Se deben crear las rutas y comportamiento que estan buscando.

+0

Esto es realmente muy útil, porque si bien es un hack dramático, abre la posibilidad de probar un enfoque diferente para la configuración de aplicaciones de rieles que más tarde podría hacer una gema o incluso presentar para su consideración en el núcleo de rieles . Me gusta esta idea, la probaré más tarde. ¡Gracias! – Andrew

+2

Muy útil, pero ¿hay alguna razón por la cual la acción de actualización no utiliza la ruta de edición? –

1

Puede usar Rack::Flash para almacenar los parámetros que desea en la sesión del usuario y luego redirigirlos a su url de formulario.

def create 
    @foo = Foo.new(params[:foo]) 
    if @foo.save 
    redirect_to foos_path, :notice => 'Created a foo.' 
    else 
    flash[:foo] = params[:foo] 
    flash[:errors] = @foo.errors 
    redirect_to new_foo_path #sorry - can't remember the Rails convention for this route 
    end 
end 

def new 
    # in your view, output the contents of flash[:foo] 
    @foo = Foo.new(flash[:foo]) 
end 
+0

Bueno, almacenarlos en sesión es viable supongo, pero lo que realmente estoy preguntando es si hay una manera de cambiar este comportamiento por defecto rieles para mostrar la url de la disposición que está haciendo en lugar de la acción que devuelve a ese diseño ... – Andrew

+0

Pero eso es lo que hace. Redirige y luego llena la vista con el contenido del flash. – stef

+0

Lo que quiero decir es que estoy preguntando si hay una manera, sin reescribir el controlador en absoluto, para contar los carriles que desea que el URL para que coincida con la plantilla prestados, en lugar de la acción del controlador que lo llamó. ¿Tiene sentido? – Andrew

2

Puede configurar el enrutamiento manualmente, si le preocupa la URL que se mostrará. Por lo desea, puede tener un GET a /foos/new hacer que su forma, y ​​una POST a la misma URL hacer la creación:

map.with_options :controller => :foos do |foo| 
    foo.new_foo '/foos/new', :conditions => {:method => :get}, :action => :new 
    foo.create_foo '/foos/new', :conditions => {:method => :post}, :action => :create 
    foo.foos  '/foos',  :conditions => {:method => :get}, :action => :index 
end 

Esto debería funcionar sin requerir ningún cambio en su controlador (! Yay) - todo tres acciones de su ejemplo son atendidas. Las pocas renuncias: - (? Semántica)

  1. Esto se basa en mi ruta para una aplicación 2.3.8 alguna sintaxis cambios probablemente se requieren para entrar en los carriles de 3 estilos de enrutamiento.
  2. Mis intentos de mezclar este estilo de enrutamiento con map.resources han fallado horriblemente, a menos que esté más familiarizado con esto que yo, o que el enrutamiento de Rails 3 sea mejor (ambos posibles), tendrá que hacer esto para cada ruta al controlador.
  3. Y, por último, no olvide agregar /:id, (.:format), etc. a las rutas que los necesitan (ninguno en este ejemplo, pero vea el n. ° 2).

Hope this helps!

Editar: Una última cosa - que necesita para codificar la URL en su ayudante en form_for/foos/new.html.erb. Simplemente agregue :url => create_foo_path, de modo que Rails no intente publicar en /foos, que lo hará de forma predeterminada (puede haber una forma de cambiar la URL de creación en el modelo, pero no lo sé, si hay alguno).

9

para responder a su comentario en otra respuesta:

Me pregunto si hay una manera, sin reescribir el controlador en absoluto, para contar los carriles que desea que el URL para que coincida con la plantilla prestados, en lugar de la acción del controlador que lo llamó.

Yo no lo creo; Las URL están vinculadas directamente al enrutamiento, que está vinculado a un par de controlador y acción: la capa de renderizado no lo toca en absoluto.

Para responder su pregunta original, aquí está la información de another similar question He respondido.


Como usted ha encontrado, de forma predeterminada cuando se especifica resources :things, la ruta de la POST para la creación de una nueva cosa está en /things. Aquí está la salida para rake routes:

things GET /things(.:format)   {:action=>"index", :controller=>"things"} 
      POST /things(.:format)   {:action=>"create", :controller=>"things"} 
new_thing GET /things/new(.:format)  {:action=>"new", :controller=>"things"} 
edit_thing GET /things/:id/edit(.:format) {:action=>"edit", :controller=>"things"} 
    thing GET /things/:id(.:format)  {:action=>"show", :controller=>"things"} 
      PUT /things/:id(.:format)  {:action=>"update", :controller=>"things"} 
      DELETE /things/:id(.:format)  {:action=>"destroy", :controller=>"things"} 

Parece que usted quiere algo más parecido a esto:

create_things POST /things/new(.:format)  {:action=>"create", :controller=>"things"} 
     things GET /things(.:format)   {:action=>"index", :controller=>"things"} 
    new_thing GET /things/new(.:format)  {:action=>"new", :controller=>"things"} 
    edit_thing GET /things/:id/edit(.:format) {:action=>"edit", :controller=>"things"} 
     thing GET /things/:id(.:format)  {:action=>"show", :controller=>"things"} 
       PUT /things/:id(.:format)  {:action=>"update", :controller=>"things"} 
       DELETE /things/:id(.:format)  {:action=>"destroy", :controller=>"things"} 

Aunque no se recomienda, puede obtener este resultado con el siguiente recorrido:

resources :things, :except => [ :create ] do 
    post "create" => "things#create", :as => :create, :path => 'new', :on => :collection 
end 

También necesitaría modificar sus formularios para que sean POST a la ruta correcta.

+3

Ok, esto más o menos responde mi pregunta (no, no hay realmente una manera bonita y limpia de hacerlo). Lo que realmente me molesta es que la URL que obtienes cuando tu nuevo registro no pasa la validación no es la URL correcta para la página que estás viendo. Si vuelves a cargar esa página, no obtienes la misma página. Eso me parece una mala decisión de diseño en los rieles internos si me preguntas, pero bueno. Dejaré esto abierto un poco más ya que acabo de otorgarle una recompensa, en caso de que alguien más tenga otras ideas. ¡Gracias! – Andrew

+1

Comprensible. Apoyo la idea de que las URL son importantes, y puedo entender esta frustración. Me pregunto si hubo algún razonamiento detrás de la elección. Pero, también tenga en cuenta que no se trata realmente de REST. Hay una gran diapositiva cubierta llamada [Mejores prácticas RESTful] (http://www.slideshare.net/calamitas/restful-best-practices) que sin duda me hizo pensar. –

+0

Desafortunadamente, ninguno de los errores de validación persiste con esta solución. – WojciechKo

Cuestiones relacionadas