En Rails 3, cuando una acción de creación de recursos falla y las llamadas se procesan: nuevo, ¿por qué la URL debe cambiar a la URL de índice del recurso?

Tengo un recurso llamado Libros. Está listado como un recurso correctamente en mi archivo de rutas.

Tengo una nueva acción, que le da a la nueva vista el estándar:

@book = Book.new 

En el modelo, hay algunos atributos que se validan por presencia, por lo que si falla una acción de guardar, se generarán errores.

En mi controlador:

 @book = Book.create ... # some logic if @book.save redirect_to(@book) else render :new end 

Esto es bastante estándar; y la razón para usar render: new es para que el objeto se devuelva a la vista y se puedan informar los errores, se puedan rellenar las entradas del formulario, etc.

Esto funciona, excepto que cada vez que me envían de vuelta al formulario (a través de render: new), aparecen mis errores, pero mi URL es la URL de índice, que es

 /books 

Más bien que

 /books/new 

Que es donde comencé en primer lugar. He visto varias otras publicaciones sobre este problema, pero no hay respuestas. Como mínimo, uno supondría que lo llevaría a / books / create, que también tengo un archivo de vista para (idéntico al nuevo en este caso).

Puedo hacer esto:

 # if the book isn't saved then flash[:error] = "Errors!" redirect_to new_book_path 

Pero luego se pierden los datos de @book, junto con los mensajes de error, que es el punto entero de tener la forma y las acciones, etc.

¿Por qué es render: new landing me at / books, mi acción de índice, cuando normalmente esa URL llama al método INDEX, que enumera todos los libros?

En realidad te está enviando a la ruta de creación. Está en la acción de create , la ruta para la cual es /books , usando el método HTTP POST. Se ve igual que la ruta del índice /books , pero la ruta del índice está usando el método HTTP GET. El código de enrutamiento de los Rails tiene en cuenta el método al determinar qué acción llamar. Después de que falla la validación, todavía estás en la acción de crear, pero estás representando la new vista. Es un poco confuso, pero una línea como render :new no invoca la nueva acción; sigue ejecutando la acción de crear y le dice a Rails que represente la nueva vista .

Acabo de empezar con Rails-Tutorial y tuve el mismo problema. La solución es simple: si desea la misma URL después de enviar un formulario (con errores), simplemente combine la acción nueva y la creación en una acción.

Aquí está la parte de mi código, que lo hace posible (espero que ayude a alguien ^^)

route.rb (añadiendo la ruta posterior para la nueva acción):

 ... resources :books post "books/new" ... 

Controlador:

 ... def create @book = Book.new(book_params) if @book.save # save was successful print "Book saved!" else # If we have errors render the form again render 'new' end end def new if book_params # If data submitted already by the form we call the create method create return end @book = Book.new render 'new' # call it explicit end private def book_params if params[:book].nil? || params[:book].empty? return false else return params.require(:book).permit(:title, :isbn, :price) end end 

new.html.erb:

 <%= form_for @book, :url => {:action => :new} do |f| %> <%= f.label :title %> <%= f.text_field :title %> <%= f.label :isbn %> <%= f.text_field :isbn %> <%= f.label :price %> <%= f.password_field :price %> <%= f.submit "Save book" %> <% end %> 

Solo tenía la misma pregunta, así que tal vez esto podría ayudar a alguien algún día. Básicamente, tienes que hacer 3 ajustes para que esto funcione, aunque mi solución todavía no es la ideal.

1) En la acción crear:

 if @book.save redirect_to(@book) else flash[:book] = @book redirect_to new_book_path end 

2) En la nueva acción:

 @book = flash[:book] ? Book.new(flash[:book]): Book.new 

3) Siempre que analice el hash de flash, asegúrese de filtrar el flash [: libro].

-> se muestra la URL correcta, se conservan los datos del formulario. Sin embargo, de alguna manera no me gusta poner el objeto de usuario en el hash flash, no creo que sea su propósito. ¿Alguien sabe un mejor lugar para ponerlo?

No te aterriza en /books/new ya que estás creando un recurso al publicar en /books/ . Cuando su creación falla, solo se muestra la nueva acción, no se le redirige a la nueva acción. Como @MrYoshiji dice anteriormente, puede intentar redirigirlo a la nueva acción, pero esto es realmente ineficiente ya que estaría creando otra solicitud HTTP y un viaje de ida y vuelta al servidor, solo para cambiar la URL. En ese punto, si es importante, probablemente pueda usar javascript para cambiarlo.

Se puede arreglar usando la misma url pero diferentes métodos para la acción nueva y de creación.

En el archivo de rutas se puede utilizar el siguiente código.

 resources :books do get :common_path_string, on: :collection, action: :new post :common_path_string, on: :collection, action: :create end 

Ahora tu nueva página se renderizará en url

libros / common_path_string

En caso de que se produzca algún error después de la validación, la URL seguirá siendo la misma.

También en el formulario en lugar de usar

 books_path 

utilizar

 url: common_path_string_books_path, method: :post 

Elija common_path_string de su agrado.

Aquí está mi solución. No estoy seguro de si es REST, y Raily y lo que sea (como todavía soy principiante), pero está funcionando, al menos todavía:

 # routes.rb post 'posts/new', to: 'posts#create', as: 'post_create' resources :posts # posts_controller.rb def new end def create if Post.save? redirect_to posts_path else render action: 'new' end # new.html.erb <%= form_with model: Post.new, url: :post_create, method: :post, local: true do |f| %> <%= f.submit 'Submit' %> 

Actualizar

A pesar de que la solución funciona técnicamente, teniendo en cuenta que el objective de create acción es la creación (y en la mayoría de los casos será positivo), voy a considerar esto:

No debe hacer que el navegador necesite hacer una llamada nueva a menos que realmente tenga que hacerlo, así que siempre pregunte cuándo está usando redirect_to y si es lo correcto, o tal vez un render sea ​​mejor.

De este articulo