我刚刚开始"Build Your Own Ruby on Rails",我不得不经常使用Google,因为这本书似乎有很多代码不起作用的地方。这一次,我找不到答案。好的,这就是交易。我有一个看起来像这样的表单:
new.html.erb
:
<%= form_for :story do |f| %>
<p>
name:<br />
<%= f.text_field :name %>
</p>
<p>
link: <br />
<%= f.text_field :link %>
</p>
<p>
<%= submit_tag %>
</p>
<% end %>
当我去localhost:3000/story/new
时,它表现得很好。问题是,当我尝试在表单中键入内容并按"提交"时,出现此错误:
Routing Error
No route matches [POST] "/story/new"
我的routes.rb
如下所示:
FirstApp::Application.routes.draw do
resources :story
story_controller
看起来像这样:
def new
@story = Story.new(params[:story])
if request.post?
@story.save
end
end
new
story_controller
的东西直接来自书中。我想我可能在这里有一个解决方案,但没有骰子。任何帮助将不胜感激。
我猜你的意思是(注意 at 符号):
<%= form_for @story do |f| %>
这可能会解决您的路由问题,但正如 John 提到的,您的控制器操作也有点偏差。 new
操作应仅加载虚拟模型并显示新的.html.erb页面 - 保存应在称为create
的单独操作中进行。
希望这有帮助!
编辑:最小的控制器代码:
class StoriesController < ApplicationController
def new
#Make a dummy story so any default fields are filled correctly...
@story = Story.new
end
def create
@story = Story.new(params[:story])
if(@story.save)
#Saved successfully; go to the index (or wherever)...
redirect_to :action => :index
else
#Validation failed; show the "new" form again...
render :action => :new
end
end
end
首先,Rails在使用单数名称与复数名称时依赖于约定而不是配置。如果要遵循约定,则必须将routes.rb
中的行更改为 resources :stories
,这将生成以下路由:
stories GET /stories(.:format) stories#index
POST /stories(.:format) stories#create
new_story GET /stories/new(.:format) stories#new
edit_story GET /stories/:id/edit(.:format) stories#edit
story GET /stories/:id(.:format) stories#show
PUT /stories/:id(.:format) stories#update
DELETE /stories/:id(.:format) stories#destroy
请注意,在这种情况下,您必须将控制器重命名为 StoriesController
。但是,您的routes.rb
具有 resources :story
,这会生成以下路由:
story_index GET /story(.:format) story#index
POST /story(.:format) story#create
new_story GET /story/new(.:format) story#new
edit_story GET /story/:id/edit(.:format) story#edit
story GET /story/:id(.:format) story#show
PUT /story/:id(.:format) story#update
DELETE /story/:id(.:format) story#destroy
如您所见,确实没有POST /story/new
的路线.我想,您收到的错误是由控制器中的以下代码触发的:
if request.post?
@story.save
end
这是完全错误的,因为您尝试在路由到的操作中检查POST
请求 GET
.只需从new
操作中删除此代码,create
操作添加到StoryController
,如下所示:
def create
@story = params[:story]
if @story.save
redirect_to @story, notice: "Story created"
else
render action: "new"
end
end
这应该可以暂时解决您的问题。但我强烈建议为您的资源使用复数stories
,因为它会再次困扰您。
您(和我)从指南中遗漏的部分:
不过,这种形式有一个问题。如果您检查 HTML生成后,通过查看页面的源代码,您将看到表单的操作属性指向/articles/new。这是一个问题,因为此路由会转到您所在的页面此刻在右侧,该路线应仅用于显示新文章的表单。
表单需要使用不同的 URL 才能转到其他地方。这可以通过 form_for 的 :url 选项非常简单地完成。通常在 Rails 中,用于新表单提交的操作像这样被称为"创建",所以形式应该指向那个动作。
编辑 app/views/articles/new.html.erb 中的form_for行
,如下所示:
<%= form_for :story, url: stories_path do |f| %>