那么,你的rails是2.3了对吧
这是REST调用的问题
参考下面内容吧
我的建议是,你先大概看看REST
首先要了解的是 REST 的概念,然后需要了解 Rails 对 REST 的理解。
接下来,这个问题就不是问题了,关键在于这个 FORM 的提交方式。REST 认为:
PUT 表示修改一个既存的资源
POST 表示创建一个新的资源
DELETE 自然表示删除
[img]http://mypages.iteye.com/upload/picture/pic/28467/1210821d-9e34-3c63-9016-7dba325191af.jpg[/img]
传统的link_to 所生成的链接中包含了controller和action,相对比,使用新的 “project_path” 所创建的链接,只包含了controller 和 资源的id –毫无疑问,这是一个 REST风格的URL。因为链接默认的是一个“Get”请求,Rails 能够知道这一点,所以就会去调用 show action。对于每一个资源,rails 都会有7个标准的 path 方法,这些可以从表1.2中看到。
每一个path 方法都关联一个 http 协议的动作,一些请求(例如show,create),可以通过http协议的 Get 或 Post 传递给服务器;但是有一些请求,如 update,delete,则需要一些其他的方式(如使用隐藏的变量)传递给服务器,因为浏览器并不知道 PUT和DELETE动作。接下来的章节我们会仔细的介绍。
进一步看看这个表,我们也会发现4个http 动作,并不足以包含全部的CRUD操作。前2个方法使用Get的方式会工作的很好,但是对于new_project_path 和 edit_project_path 就不同了。
New 和 Edit
用户如果点击一个“新建”链接,那么会使用Get动作来对服务器发送一个请求。下面的例子表明,生成的链接是由 controller 和一个“new”action 组成的。
[code="ruby"]link_to "New", new_project_path
=>
New[/code]
这是对REST思想的一种破坏?或许乍看之下确实如此。但是如果你仔细看,那么一切都会清晰,“new”并不是一个CURD的action,它更像一个建立一个新的资源之前的准备的动作。真正的CRUD 中的create被调用,是在新的form被提交的以后才执行的。这个链接当然也没有资源的id—因为资源还没有被创建。一个链接如果没有资源的id,那么就不应该被称为REST的URL,因为REST的URL总是会指定一个资源的id。所以,这个 “new” action 仅仅因该用来显示一个新的form的页面而已。
对于 edit_project_path ,也是同样的道理。它引用了一个资源,但是仅仅是在调用 update action 之前的准备工作。真正的update action 是在页面被提交以后才执行的。edit_project_path 和 new_project_path 唯一的区别就是前者需要使用一个资源的id。按照REST的规则,资源的id放在controller 的后面:/project/1 。但是如果仅仅使用Get 动作来提交这个URL,那么Rails将会认为你要调用的是show action。为了防止这一点,edit_project_path 方法扩展了一下生成的链接,例如:
[code="ruby"]link_to "Edit", edit_project_path(project)
=>
Edit[/code]
这样,我们就能理解为什么允许 edit_project_path 和 new_project_path生成的链接里带有 action 了,因为他们两个都不是REST的 CRUD URL,他们仅仅是准备工作。还有其它的一些URL和这两个很相似,我们会在后面的章节介绍。
在 form 中使用 path 方法:Create 和 Update
传统的方式上,我们使用 form_tag 或 form_for 来创建一个form:
[code="ruby"]<% form_for :project, @project, :url => { :action => "create" } do |f|
%>
...
<% end %>[/code]
在REST应用中,这个 :url hashmap 会被 path 方法给取代:
“project_path” 创建新的资源所使用的form
“project_path(:id)”编辑一个资源所使用的form
a) 创建资源所使用的form
form 使用 post 动作向服务器提交信息,“project_path”方法并不会有资源id作为参数,这样,生成的URL就应该是“/projects”这个样子。当提交到服务器以后,就会调用 create action。
[code="ruby"]form_for(:project, :url => projects_path) do |f| ...
=>
[/code]
b) 编辑一个资源所使用的form
按照REST的思想,一个更新的操作是使用http协议的PUT动作来发送的。但是,正如我们所知道的,浏览器只明白 Post和Get动作。解决的办法就是使用
form_for 方法里的 :html 参数。
[code="ruby"]form_for(:project, :url => project_path(@project),
:html => { :method => :put }) do |f| ...
=>
[/code]
Rails 生成了一个隐藏的字段来代替http的put 动作。提交以后,Rails 会检查这个变量,然后判断是否去调用update方法。
删除
恐怕我们已经发觉了,用于显示和删除一个资源,所使用的path方法都一样:
[code="html"]link_to "Show", project_path(project)
link_to "Destroy", project_path(project), :method => :delete[/code]
唯一的不同就是 删除的时候,使用了一个变量 :method,用它来表示http的DELETE动作。因为浏览器不支持DELETE动作,所以,Rails 会生成一些javascript来解决这个问题:
[code="js"]link_to "Destroy", project_path(project), :method => :delete
=>
onclick="var f = document.createElement(’form’);
f.style.display = ’none’; this.parentNode.appendChild(f);
f.method = ’POST’; f.action = this.href;
var m = document.createElement(’input’);
m.setAttribute(’type’, ’hidden’);
m.setAttribute(’name’, ’_method’);
m.setAttribute(’value’, ’delete’); f.appendChild(m);f.submit();
return false;">Destroy[/code]
这段javascript 会生成一个form,把 http 的DELETE动作放在隐藏变量里传递给服务器,然后,Rails 会判断这个变量,决定是否去调用destroy 方法。