我有一个名为Books的资源。它在我的路由文件中正确地列为资源。
我有一个新操作,它为新视图提供了标准:
@book = Book.new
在模型上,有一些属性可以通过在场验证,因此,如果保存操作失败,将产生错误。
在我的控制器中:
@book = Book.create
... # some logic
if @book.save
redirect_to(@book)
else
render :new
end
这是非常标准的;并且使用render:new的原理是这样,以便将对象传递回视图,并可以报告错误,重新填写表单项,等等。
这有效,除了每次我通过render:new发送回表单时,都会显示我的错误,但是我的URL是INDEX URL,它是
/books
而不是
/books/new
首先是我从哪里开始的。我看过其他一些有关此问题的帖子,但没有答案。至少,有人会假设它会把您带到/ books / create,我也有一个视图文件(在这种情况下,与new相同)。
我可以这样做:
# if the book isn't saved then
flash[:error] = "Errors!"
redirect_to new_book_path
但是随后,@ book数据以及错误消息将丢失,这是具有表单和操作等的全部内容。
为什么render:new使我进入/ books,我的索引操作,通常该URL调用INDEX方法,该方法列出所有书籍?
实际上是是将您发送到创建路径。它使用HTTP方法POST在create
操作中,其路径为/books
。这看起来与索引路径/books
相同,但是索引路径使用的是HTTP方法GET。在确定调用哪个动作时,rails路由代码会考虑该方法。验证失败后,您仍处于create动作中,但是正在渲染new
视图。这有点令人困惑,但是像render :new
这样的行实际上根本没有调用新动作;它仍在运行create操作,并告诉Rails渲染新的view。
我刚开始使用Rails-Tutorial,并且遇到了同样的问题。解决方案很简单:如果提交表单后(错误)想要相同的URL,只需将new和create动作组合在一个动作中。
这是我的代码的一部分,这使得这成为可能(希望它可以帮助某人^^)
routes.rb(为新操作添加后路由):
...
resources :books
post "books/new"
...
控制器:
...
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 %>
只是有一个非常相同的问题,所以也许有一天某人会有所帮助。为了使此功能正常运行,您基本上必须进行3次调整,尽管我的解决方案仍然不理想。
1)在创建动作中:
if @book.save
redirect_to(@book)
else
flash[:book] = @book
redirect_to new_book_path
end
2)在新动作中:
@book = flash[:book] ? Book.new(flash[:book]): Book.new
3)无论您在哪里解析Flash哈希,请务必过滤掉Flash [:book]。
->显示正确的URL,保留表单数据。尽管如此,我还是不喜欢将用户对象放入闪存哈希中,我不认为这是目的。有没有男孩知道更好的放置位置?
由于您通过发布到/books/new
来创建资源,因此它不会降落在/books/
上。当创建失败时,它只是呈现新动作,而不是将您重定向到新动作。就像@MrYoshiji在上面说的那样,您可以尝试将其重定向到新操作,但这确实效率不高,因为您将创建另一个HTTP请求并往返于服务器,仅更改URL。到那时,如果很重要,您可以使用javascript对其进行更改。
可以通过使用相同的url,但是使用不同的new和create动作方法来修复它。
在路由文件中,可以使用以下代码。
resources :books do
get :common_path_string, on: :collection, action: :new
post :common_path_string, on: :collection, action: :create
end
现在,您的新页面将在URL呈现
books / common_path_string
如果在验证后出现任何错误,则URL仍将相同。
也以表格的形式使用
books_path
使用
url: common_path_string_books_path, method: :post
选择您喜欢的common_path_string。