rails 自定义 Action

本文详细介绍了如何在Rails框架下自定义非CRUD操作的API,包括修改数据库、创建链接、定义路由及实现自定义action的方法。通过实例展示了如何处理关闭资源的功能,以及如何在控制器中编写相关代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

自定义 Action

我们已经知道,在 /config/routes.rb 里定义的路由,会自动生成对资源的CRUD的操作。但是我们如何处理那些并不是CRUD的操作?下面我们就用一个例子来说明这一点。例如我们在 ProjectController里有一个close的方法。这个close并不是真正的删除一个资源,而只是把给这个资源设置一个标志:表示这个
资源被关闭了。

首先修改一下数据库:
> ruby script/generate migration add_closed_to_projects
exists db/migrate
create db/migrate/003_add_closed_to_projects.rb
Listing 1.16: ontrack/db/migrate/003 add closed to projects.rb
class AddClosedToProjects < ActiveRecord::Migration
def self.up
add_column :projects, :closed, :boolean, :default => false
end
def self.down
remove_column :projects, :closed
end
end
rake db:migrate


现在,我们在IteratinController的index.rhtml上创建一个 close 的链接。


Listing 1.17: ontrack/app/views/projects/index.rhtml
<% for project in @projects %>
<tr id="project_<%= project.id %>">
<td><%=h project.name %></td>
<td><%= link_to "Show", project_path(project) %></td>
...
<td><%= link_to "Close", <WHICH_HELPER?> %></td>
</tr>
<% end %>


现在有2个问题摆在我们面前:
1.使用 http 协议的哪个动作来发送这个请求呢?
2.对于这个链接,该如何生成那些 helper方法呢?


因为这个 close 动作并不是CRUD中的任何一个,所以Rails 也不知道该用http的哪个来做这个事情。不过既然 close 也是 update 中的一种,所以应该使用post来发送这个请求。我们还是得在 /config/routes.rb 里定义这个路由,当然定义完路由之后,就会有相应的path和url的helper方法了。因为这个close的操作,仍然是针对projects 这个资源的,所以,我们可以在定义路由的时候,使用一个名字叫“member”的hashmap,这个hashmap 的key,就是自定义action的名字,hashmap的value,就是所使用的http的动作。

map.resources :projects, :member => { :close => :post }


hashmap 的value可以使用 :get, :put, :post, :delete, :any。如果使用了:any,那么可以用http的任何动作来发送这个请求。


定义完这个路由后,我们就可以使用helper方法了:
<td><%= link_to "Close", close_project_path(project) %></td>


因为我们定义的是“:member => { :close => :post }”,所以,这个请求只能以post的方式来发送,如果使用其它方式如“get”,那么请求就是无效的。为了安全起见,我们还是把它改成用按钮的方式来发送,幸运的是我们可以使用Rails 提供的button_to 来做这件事情:


<td><%= button_to "Close", close_project_path(project) %></td>
=>
<td>
<form method="post" action="/projects/1;close" class="button-to">
<div><input type="submit" value="Close" /></div>
</form>
</td>


现在我们要做的就是写完 ProjectController中的 close 方法:
Listing 1.18: ontrack/app/controllers/projects controller.rb
def close
respond_to do |format|
if Project.find(params[:id]).update_attribute(:closed, true)
flash[:notice] = "Project was successfully closed."
format.html { redirect_to projects_path }
format.xml { head :ok }
else
flash[:notice] = "Error while closing project."
format.html { redirect_to projects_path }
format.xml { head 500 }
end
end
end


除了“:member”,我们还可以使用“:collection”,“:new”。
“:collection”的用途是:所操作的资源不是一个,而是很多个。下面是一个用“:collection”方式得到一个资源的列表的例子:
map.resources :projects, :collection => { :rss => :get }
--> GET /projects;rss (maps onto the #rss action)


所以,有的时候,“:member”更多的是更新一个资源,而“:collection”是得到一堆资源。
对于“:new”,一般用于那些还没有被保存的资源:
map.resources :projects, :new => { :validate => :post }
--> POST /projects/new;validate (maps onto the #validate action)

我们是否仍然“DRY”(Don’t Repeat Yourself)?

我们是否为了“DRY”原则?似乎是这样的:我们不仅在controller里定义了action,同时在 /config/routes.rb 里也定义了一遍。


作为替换REST风格的调用的方式,您可以用传统的方式来调用一个方法:
<%= link_to "Close", :action => "close", :id => project %>


但是别忘了,即使用传统的方式,你也得在/config/routes.rb里定义一个路由:“map.connect ’:controller/:action/:id’”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值