自定义 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’”。
自定义信息格式
目前 respond_to 可以返回如下的信息格式:
respond_to do |wants|
wants.text
wants.html
wants.js
wants.ics
wants.xml
wants.rss
wants.atom
wants.yaml
end
你可以通过增加新的MIME类型的信息来扩展这个功能。假设您已经开发了一个“PIM”应用系统,现在你希望把地址信息用”vcard” 格式来传送。要实现这一共能,首先你需要注册新的信息格式在
/config/environment.rb。
Mime::Type.register "application/vcard", :vcard然后,我们来修改一下show action,使得返回的信息以vcard 的格式来传送。
def show
@address = Address.find(params[:id])
respond_to do |format|
format.vcard { render :xml => @address.to_vcard }
...
end
end
这个 to_vcard 方法不是 ActiveRecord 的标准方法,所以必须按照
vcard的标准来实现(RFC2426)。如果实现正确的话,那么通过下面的URL,就可以得到正确的信
息:“http://localhost:3000/addresses/1.vcard”。
在REST 中使用AJAX
在REST风格的系统中使用AJAX?非常简单,可以说这一小节没什么新鲜的玩意要学习。您还是使用以前所使用的 remote
系列的helper 方法,只不过传递的参数需要改变,现在使用 path helper 方法,而不是以前所使用的
contoller,action 。下面的例子会让您更清晰的明白这一点:
link_to_remote "Destroy", :url => project_path(project),
:method => :delete
=>
<a href="#" onclick="new Ajax.Request("/projects/1",
{asynchronous:true, evalScripts:true, method:"delete"});
return false;">Async Destroy</a>
给您提醒一下:千万千万记得导入相应的ajax javascript 文件,不然当您的ajax无效,而气得把键盘砸坏的时候,我们就无能为力了。导入相应的javascript 文件相当的简单:
Listing 1.19: ontrack/app/views/layouts/projects.rhtml
<head>
<%= javascript_include_tag :defaults %>
...
</head>
这个“Destroy”链接将会调用ProjectsController的destroy方法。从逻辑上来说现在一切正常:用户点这个链接,系统删除相
应的资源。不过我们还是漏了一点:在 respond_to 中,我们应该增加新的返回类新,也就是javascript类型。
Listing 1.20: ontrack/app/controllers/projects controller.rb
def destroy
@project = Project.find(params[:id])
@project.destroy
respond_to do |format|
format.html { redirect_to projects_url }
format.js # default template destroy.rjs
format.xml { head :ok }
end
end
可以看出来,唯一的改变就是增加了“format.js”。因为这个“format.js”并不是一个要被执行的代码块,所以,Rails 会按照标准显示destroy.rjs。
Listing 1.21: ontrack/app/views/projects/destroy.rjs
page.remove "project_#{@project.id
}"
这个 rjs 文件从当前的浏览页面中删除了 “project_ID”这个DOM元素,为了让这个删除起到效果,我们就需要在显示 project 上进行修改:
Listing 1.22: ontrack/app/views/projects/index.rhtml
...
<% for project in @projects %>
<tr id="project_<%= project.id %>">
这是一个遵循DRY原则和减少对当前系统的修改的一个好例子!也体现了REST的优势,只需要在controller里增加一行,就可以处理javascript请求了。
同时也告诉了我们一个REST编程的原则:在 respond_to 外实现逻辑处理,能够极大地降低重复的代码。
测试
不管开发REST风格的应用是多么的让我们激动,我们也不能忘记最重要的一个朋友:测试!
之前我们写了那么多代码,但是一次单元测试测试都没运行过!下面我们来运行一下吧!
> rake
...
Started
EEEEEEE.......
好消息是,所有的单元测试和功能测试都可以运行。坏消息是,关于IterationsController的7个功能测试,全部失败!
如果测试用例抛出异常,那么很明显的—这里存在一些错误。我们遇到的错误也很明显:所有的IterationsController的测试用例都是
scaffold 来生成的,并没有一个“父”资源的关联—还记得吗,我们已经让iterations 资源成为了projects 资源的“子”资源。
为了让我们的测试用例通过,我们必须给每个测试方法都增加project_id。例如:
Listing 1.23: ontrack/test/functional/iterations controller test.rb
def test_should_get_edit
get :edit, :id => 1, :project_id => projects(:one)
assert_response :success
end
当然了,你需要加载必要的fixtures:
fixtures :iterations, :projects
改完全部的测试用例以后,我们发现还是有2个测试用例无法通过:
test_should_create_iteration
test_should_update_iteration
失败的代码来自这行“assert_redirected_to iteration_path(assigns(:iteration))”。
错误是非常显然的:我们已经知道iteration_path的第一个参数应该是project id。我们同样需要修改一下:
assert_redirected_to iteration_path(projects(:one), assigns(:iteration))
另外,在使用 redirect 断言的时候,path helper 方法的使用,是REST和非REST风格应用的唯一区别。
REST 风格的客户端:ActiveResource
我们总是把 ActiveResource 和 REST一起提及。ActiveResource 是一个Rails 的库,用来开发基于REST的WEB服务客户端。这种基于REST的客户端,也是适用 http 的4个标准的动作来和服务器通信。
ActiveResource 并不是Rails 1.2 的一部分,但是您可以使用svn 从网站下载它的代码:
> cd ontrack/vendor
> mv rails rails-1.2
> svn co http://dev.rubyonrails.org/svn/rails/trunk
rails
ActiveResource把客户端资源抽象成一个类,这个类继承自ActiveResource::Base。例如通过下面的例子,我们来调用服务器上的project 资源:
require "activeresource/lib/active_resource"
class Project < ActiveResource::Base
self.site = "http://localhost:3000
"
end
可以看到,我们导入了ActiveResource 的库,然后,服务器的地址赋给了类的变量 site。这个 Project 类,把服务器上的资源抽象成了一个客户端的类,这就让开发人员觉得他们就好像操作一个ActiveRecord 一样。
例如,我们用一个project id 和 find 方法去请求服务器上的一个资源:
wunderloop = Project.find 1
puts wunderloop.name
这个 find 方法会执行标准的GET动作:GET /projects/1.xml
然后服务器返回xml格式的信息。客户端把xml信息转化成一个ActiveResource对象 wunderloop,就好像一个ActiveRecord对象,可以得到和改变它的任何属性。那么我们如何去更新一个资源呢?
wunderloop.name = "Wunderloop Connect"
wunderloop.save
save 方法会是用put 动作向服务器传递信息。
PUT /projects/1.xml
刷新一下你的浏览器看看,那条记录肯定被改变了。和 find,save一样简单,创建一个新的资源也是非常方便:
bellybutton = Project.new(:name => "Bellybutton")
bellybutton.save
新的资源将会以post方式传递给服务器,并且保存到数据库里。
POST /projects.xml
刷新浏览器,会看到新建立的资源。最后,我们来看一下删除一个资源。
bellybutton.destroy
destroy方法将会以DELETE方式发送给服务器,并且删除这个资源。
DELETE /projects/2.xml
ActiveResource 使用http的4个动作来和服务器交互。对于REST的资源,它提供了非常好的抽象,此外,在ActiveRecord中的许多方法,在ActiveResource中仍然找得到。例如查找一个资源的全部记录:
Project.find(:all).each do |p|
puts p.name
end
相信使用ActiveResource可以开发出很好的松耦合的系统,我们不如马上去下载ActiveResource的代码,亲自体验一下吧!
大结局
这个世界并不是非得需要REST。有很多的解决方案可以考虑,并且可以很容易实现。大概更多的时候,是您可能现在正处于某个项目的中期,这时,您发
现了Rails这个新特性。我想如果您此时就开发一个单独的模块,并且使用REST的风格,是毫无问题的。如果您要准备开始一个全新的项目,那么不妨考虑
一下使用
REST,理由十分明显:清晰的架构,更少的代码,多个客户端的支持。
终于结束了,有关rails2.0 rest风格的新特性建议看一篇文章叫"Rolling with Rails 2.0 - The First Full Tutorial
"。http://www.iteye.com/topic/162536
相关推荐
基于智能温度监测系统设计.doc
包括userCF,itemCF,MF,LR,POLY2,FM,FFM,GBDT+LR,阿里LS-PLM 基于深度学习推荐系统(王喆)
2023-04-06-项目笔记-第三百五十五阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.353局变量的作用域_353- 2024-12-22
和美乡村城乡融合发展数字化解决方案.docx
基于Python的深度学习图像识别系统是一个利用卷积神经网络(CNN)对图像进行分类的先进项目。该项目使用Python的深度学习库,如TensorFlow,构建和训练一个模型,能够自动识别和分类图像中的对象。系统特别适合于图像处理领域的研究和实践,如计算机视觉、自动驾驶、医疗影像分析等。 项目的核心功能包括数据预处理、模型构建、训练、评估和预测。用户可以上传自己的图像或使用预定义的数据集进行训练。系统提供了一个直观的界面,允许用户监控训练进度,并可视化模型的性能。此外,系统还包括了一个模型优化模块,通过调整超参数和网络结构来提高识别准确率。 技术层面上,该项目使用了Python编程语言,并集成了多个流行的机器学习库,如NumPy、Pandas、Matplotlib等,用于数据处理和可视化。模型训练过程中,系统会保存训练好的权重,以便后续进行模型评估和预测。用户可以通过简单的API调用,将新的图像输入到训练好的模型中,获取预测结果。
拳皇97.exe拳皇972.exe拳皇973.exe
基于python和协同过滤算法的电影推荐系统 基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法
DEV-CPP-RED-PANDA
Python语言求解旅行商问题,算法包括禁忌搜索、蚁群算法、模拟退火算法等。
pdfjs 用于在浏览器中查看/预览/打印pdf。 pdfjs 2.5.207 支持firefox/chrome/edge/ie11以上版本。 如果需要支持旧版本浏览器,可以使用这个,是未修改过的原版,支持打印和下载按钮。亲测有效。 pdf 4.9.155分两个包: pdfjs-4.9.155-dist.zip pdfjs-4.9.155-legacy-dist.zip
建设项目现场高温人员中暑事故应急预案
数据结构上机实验大作业-线性表选题.zip
【资源说明】 基于高德地图的校园导航全部资料+详细文档+高分项目.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
【静态站群程序视频演示,只有视频,不含程序,下载须知】【静态站群程序视频演示,只有视频,不含程序,下载须知】全自动批量建站快速养权重站系统【纯静态html站群版】:(GPT4.0自动根据关键词写文章+自动发布+自定义友链+自动文章内链+20%页面加提权词)
9.30 SWKJ 男头7张+女头2张.zip
项目已获导师指导并通过的高分毕业设计项目,可作为课程设计和期末大作业,下载即用无需修改,项目完整确保可以运行。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。 项目都经过严格调试,确保可以运行!可以放心下载 技术组成 语言:java 开发环境:idea、vscode 数据库:MySql5.7以上 部署环境:maven 数据库工具:navicat
一个通过单片机在各种屏幕上显示中文的解决方案.7z
图像
一、用户管理功能 用户注册与登录 学生注册:学生可以通过手机号、邮箱、社交账号等方式注册,填写个人信息(如姓名、年龄、学校等)。 家长/监护人账户:支持家长/监护人注册并管理学生账户,查看学习进度和成绩。 教师账户:教师可以注册并设置个人资料,上传资质认证文件。 管理员账户:管理员负责整个系统的管理,包括用户管理、课程管理、平台设置等。 用户权限管理 角色权限:系统根据用户类型(学生、家长、教师、管理员)分配不同权限,确保信息安全。 家长监督:家长可以查看子女的学习进度、成绩和教师反馈,参与学习监督。 个人资料管理 用户可以在个人中心更新基本信息,设置个人头像、联系方式、密码等。 支持学籍信息的维护,例如学生的年级、班级、课程历史等。 二、课程管理功能 课程设置 课程创建与编辑:教师或管理员可以创建和编辑课程内容,上传课件、视频、文档等教学材料。 课程分类:根据学科、年级、难度等维度进行课程分类,方便学生浏览和选择。 课程排课:管理员可以设置课程的时间表、教学内容和授课教师,并调整上课时间和频率。 课程安排与通知 课程预约:学生可以在线选择并预约感兴趣的课程,系统根据学生的时
内容概要:本文档介绍了英特尔2021年至2024年的网络连接性产品和智能处理单元(IPU)的战略和技术路线图。涵盖了从10GbE到200GbE的不同系列以太网适配器的特性、性能和发布时间。详细列出了各个产品的关键功能,如PCIe接口、安全特性、RDMA支持等。同时,介绍了IPU的发展计划,包括200G、400G和800G的不同代次产品的性能提升和新的功能特点。 适合人群:从事网络工程、数据中心管理、IT架构设计的专业技术人员。 使用场景及目标:本文档主要用于了解英特尔未来几年在以太网适配器和IPU领域的技术和产品规划,帮助企业在采购和部署网络设备时做出决策。同时,为研究人员提供最新技术发展趋势的参考。 其他说明:文档内容涉及的技术细节和时间表可能会有变动,请以英特尔官方发布的最新信息为准。