J'ai une ressource appelée Livres. Il est répertorié comme une ressource correctement dans mon fichier de routes.
J'ai une nouvelle action, qui donne à la nouvelle vue la norme:
@book = Book.new
Sur le modèle, certains attributs sont validés par la présence, donc si une action de sauvegarde échoue, des erreurs seront générées.
Dans mon contrôleur:
@book = Book.create
... # some logic
if @book.save
redirect_to(@book)
else
render :new
end
C'est assez standard; et la justification de l'utilisation de render: new est pour que l'objet soit renvoyé à la vue et que des erreurs puissent être signalées, des entrées de formulaire remplies à nouveau, etc.
Cela fonctionne, sauf que chaque fois que je suis renvoyé au formulaire (via render: new), mes erreurs apparaissent, mais mon URL est l'URL INDEX, qui est
/books
Plutôt que
/books/new
C'est là que j'ai commencé en premier lieu. J'ai vu plusieurs autres articles sur ce problème, mais aucune réponse. Au minimum, on pourrait supposer que cela vous amènerait à/books/create, pour lequel j'ai également un fichier de vue (identique à nouveau dans ce cas).
Je peux le faire:
# if the book isn't saved then
flash[:error] = "Errors!"
redirect_to new_book_path
Mais alors les données @book sont perdues, ainsi que les messages d'erreur, ce qui est tout l'intérêt d'avoir le formulaire et les actions, etc.
Pourquoi est-ce que render: new m'arrive dans/books, mon action d'index, alors que normalement cette URL appelle la méthode INDEX, qui répertorie tous les livres?
En fait, est vous envoie vers le chemin de création. C'est dans l'action create
, dont le chemin est /books
, en utilisant la méthode HTTP POST. Cela ressemble au chemin d'index /books
, mais le chemin d'index utilise la méthode HTTP GET. Le code de routage Rails prend en compte la méthode lors de la détermination de l'action à appeler. Après l'échec de la validation, vous êtes toujours dans l'action de création, mais vous rendez le new
C'est un peu déroutant, mais une ligne comme render :new
n'invoque pas du tout la nouvelle action; il exécute toujours l'action de création et il indique Rails pour rendre le nouveau voir.
Je viens de commencer avec le Rails-Tutorial et j'ai eu le même problème. La solution est simple: si vous voulez la même URL après avoir soumis un formulaire (avec des erreurs), combinez simplement la nouvelle et créez l'action en une seule action.
Voici la partie de mon code qui rend cela possible (j'espère que ça aide quelqu'un ^^)
routes.rb (Ajout de la post-route pour une nouvelle action):
...
resources :books
post "books/new"
...
Manette:
...
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 %>
Je viens de poser la même question, alors peut-être que cela pourrait aider quelqu'un un jour. Vous devez essentiellement faire 3 ajustements pour que cette chose fonctionne, bien que ma solution ne soit toujours pas idéale.
1) Dans l'action de création:
if @book.save
redirect_to(@book)
else
flash[:book] = @book
redirect_to new_book_path
end
2) Dans la nouvelle action:
@book = flash[:book] ? Book.new(flash[:book]): Book.new
3) Où que vous analysiez le hachage du flash, assurez-vous de filtrer le flash [: livre].
-> l'URL correcte s'affiche, les données du formulaire sont conservées. Pourtant, je n'aime pas du tout mettre l'objet utilisateur dans le hachage flash, je ne pense pas que ce soit son but. Quel garçon connaît-il un meilleur endroit pour le mettre?
Il ne vous atterrit pas à /books/new
puisque vous créez une ressource en publiant sur /books/
. Lorsque votre création échoue, elle rend simplement la nouvelle action, pas vous redirige vers la nouvelle action. Comme @MrYoshiji le dit ci-dessus, vous pouvez essayer de le rediriger vers la nouvelle action, mais cela est vraiment inefficace car vous créeriez une autre demande HTTP et un aller-retour vers le serveur, uniquement pour changer l'URL. À ce stade, si cela est important, vous pouvez probablement utiliser javascript pour le modifier.
Il peut être corrigé en utilisant la même URL mais différentes méthodes pour une nouvelle action et créer une action.
Dans le fichier routes, le code suivant peut être utilisé.
resources :books do
get :common_path_string, on: :collection, action: :new
post :common_path_string, on: :collection, action: :create
end
Maintenant, votre nouvelle page s'affichera à l'URL
livres/common_path_string
Si des erreurs surviennent après la validation, l'URL sera toujours la même.
Également dans le formulaire à la place en utilisant
books_path
utilisation
url: common_path_string_books_path, method: :post
Choisissez common_path_string à votre convenance.