ActionController::Resources + ActiveResource = REST

本文探讨了Rails中ActionController::Resources与ActiveResource的区别及联系,详细介绍了ActiveResource如何简化RESTful Web服务客户端开发,并展示了实际应用示例。
从Rails的svn资源库下载最新的Rails,我们会发现多了个activeresource包
从此Rails核心模块变为: ActiveRecord、ActionPack、ActionWebService、AcionMailer、ActiveResource、ActiveSupport和Railties

这里有几个问题:

[b]一,ActionController里的resources.rb文件与ActiveResource是什么关系?[/b]

当初我看到Edge Rails里多了activeresource这个包时,我第一反应就是ActionController::Resources被ActiveResource替代了吧?
但是我去ActionPack里一看,resources.rb文件依然存在,原来我的判断错了: [color=red]ActionController::Resources != ActiveResource[/color]

ActionController::Resources的工作就是创建了map.resource(s)这个DSL
这个DSL的底层含义是为一组或单个resource(其实是一组或单个对象)做两样事情:
a,生成一组named routes命名
b,为一组http动词(:get/:post/:put/:delete)做一个到一组action(index/new/create/show/edit/update/destroy)的映射
ActionController::Resources是REST风格的Rails实现,它的目的就是让我们做RESTful风格的Rails开发
按ActionController::Resources的指导,我们依照HTTP method规范开发系统,可以对html和xml两种response格式render内容
[color=blue]但我们慢慢发现,ActionController::Resources只为我们提供了REST web service的发布功能,而没有提供消费功能![/color]

ActiveResource的工作看看官方说法则不言而喻了:
[quote]
Active Resource (ARes) connects business objects and Representational State Transfer (REST)
web services. It implements object-relational mapping for REST webservices to provide transparent
proxying capabilities between a client (ActiveResource) and a RESTful service (which is provided by Simply RESTful
routing in ActionController::Resources).
[/quote]
[color=blue]ActiveResource不是ActionController::Resources的替代者,而是REST web service的消费者[/color]
Active Resource是一个proxy的角色,它连接model与service,加上一点胶水,让REST web service的调用简化无比
Active Resource的架构类似于ActiveRecord,等会我们看看代码来加深认识

[b]二,Rails有ActionWebService,还要ActiveResource干什么?[/b]

这个问题是刚才在JavaEye上看到的,其实应该说ActionWebService和ActionController::Resources+ActiveResource才有可比性
最大的区别就是ActionWebService是基于SOAP的,而ActionController::Resources和ActiveResource则是基于轻量的REST、XML的
ActionWebService是Rails对SOAP web service的封装,并提供Client端调用API
不过ActionWebService也支持XML-RPC协议

[b]三,ActiveResource尝鲜[/b]

看代码吧!
[code]
class Person < ActiveResource::Base
self.site = "http://api.people.com:3000/"
end
[/code]
Person类继承ActiveResource::Base,然后调用site=这个类方法,参数为一个URL
就这么简单,现在Person已经映射到如下RESTful resources位置: http://api.people.com:3000/people/
==== Create:
[code]
p = Person.create(:name => 'Robbin')

# POST http://api.people.com:3000/people.xml
# Submit:
# <person><name>Robbin</name></person>
[/code]
==== Find:
[code]
p = Person.find(1)

# GET http://api.people.com:3000/people/1.xml
# Response:
# <person><id>1</id><name>Robbin</name></person>

people = Person.find(:all)

# GET http://api.people.com:3000/people.xml
# Response:
# <people>
# <person><id>1</id><first>Robbin</first></person>
# <person><id>2</id><first>Gigix</first></person>
# </people>
[/code]
==== Update:
[code]
p = Person.find(1)
p.name = 'Hideto'
p.save

# PUT http://api.people.com:3000/people/1.xml
# Submit:
# <person><name>Hideto</name></person>
[/code]
==== Delete:
[code]
p = Person.find(2)
p.destroy

# DELETE http://api.people.com:3000/people/2.xml
[/code]

ActiveResource基于HTTP协议并充分使用HTTP规范里的动词:
* GET requests are used for finding and retrieving resources.
* POST requests are used to create new resources.
* PUT requests are used to update existing resources.
* DELETE requests are used to delete resources.

而Person类就是对http://api.people.com:3000/people/链接上的REST web service的代理,我们可以像使用ActiveRecord对象一样使用ActiveResource对象

[b]四、ActiveResource源码分析一二[/b]
active_resource/base.rb:
[code]
module ActiveResource
class Base

class << self
def site
if defined?(@site)
@site
elsif superclass != Object and superclass.site
superclass.site.dup.freeze
end
end
def site=(site)
@connection = nil
@site = site.nil? ? nil : create_site_uri_from(site)
end
def create(attributes = {})
returning(self.new(attributes)) { |res| res.save }
end
def find(*arguments)
scope = arguments.slice!(0)
options = arguments.slice!(0) || {}
case scope
when :all then find_every(options)
when :first then find_every(options).first
when :one then find_one(options)
else find_single(scope, options)
end
end
private
def find_every(options)
case from = options[:from]
when Symbol
instantiate_collection(get(from, options[:params]))
when String
path = "#{from}#{query_string(options[:params])}"
instantiate_collection(connection.get(path, headers) || [])
else
prefix_options, query_options = split_options(options[:params])
path = collection_path(prefix_options, query_options)
instantiate_collection( (connection.get(path, headers) || []), prefix_options )
end
end
def create_site_uri_from(site)
site.is_a?(URI) ? site.dup : URI.parse(site)
end
end

attr_accessor :attributes

def destroy
connection.delete(element_path, self.class.headers)
end

end
end
[/code]
我们看到find、create、destroy都是使用connection来做具体的操作,让我们再看connection.rb:
[code]
module ActiveResource
class Connection

def get(path, headers = {})
xml_from_response(request(:get, path, build_request_headers(headers)))
end
def delete(path, headers = {})
request(:delete, path, build_request_headers(headers))
end
def put(path, body = '', headers = {})
request(:put, path, body.to_s, build_request_headers(headers))
end
def post(path, body = '', headers = {})
request(:post, path, body.to_s, build_request_headers(headers))
end
private
def http
unless @http
@http = Net::HTTP.new(@site.host, @site.port)
@http.use_ssl = @site.is_a?(URI::HTTPS)
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @http.use_ssl
end
@http
end
def request(method, path, *arguments)
logger.info "#{method.to_s.upcase} #{site.scheme}://#{site.host}:#{site.port}#{path}" if logger
result = nil
time = Benchmark.realtime { result = http.send(method, path, *arguments) }
logger.info "--> #{result.code} #{result.message} (#{result.body.length}b %.2fs)" % time if logger
handle_response(result)
end
def handle_response(response)
case response.code.to_i
when 200...400
response
when 404
raise(ResourceNotFound.new(response))
when 405
raise(MethodNotAllowed.new(response))
when 409
raise(ResourceConflict.new(response))
when 422
raise(ResourceInvalid.new(response))
when 401...500
raise(ClientError.new(response))
when 500...600
raise(ServerError.new(response))
else
raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
end
end
end
end
[/code]
核心代码就是这些,最后只是调用Net::HTTP对象的get/post/put/delete方法,socket连接而已
主要是我们的REST web service host(如http://api.people.com:3000/)已经成功发布web服务,我们访问相应的url即可(如people.xml、people/1.xml)
ActiveResource以我们熟悉的ActiveRecord操作方式来封装和架构我们的REST web service客户端API以简化开发,我们只能说两个字:佩服!

[b]五、ActionController::Resources的一些改动[/b]

[url=http://dev.rubyonrails.org/changeset/6485]Changeset 6485[/url]
源码:
[code]
def map_collection_actions(map, resource)
resource.collection_methods.each do |method, actions|
actions.each do |action|
action_options = action_options_for(action, resource, method)

map.deprecated_named_route("#{action}_#{resource.name_prefix}#{resource.plural}", "#{resource.name_prefix}#{action}_#{resource.plural}", "#{resource.path}/#{action}", action_options)
map.deprecated_named_route("formatted_#{action}_#{resource.name_prefix}#{resource.plural}", "formatted_#{resource.name_prefix}#{action}_#{resource.plural}", "#{resource.path}/#{action}.:format", action_options)
end
end
end
[/code]
“/messages/1;edit”这种url已经替换成“/messages/1/edit”,早该这样了不是吗?

[url=http://dev.rubyonrails.org/ticket/8251]Ticket #8251[/url]
源码例子和上面一样,name_prefix放到path的最前面去了,action名字挪到它后面
先展示下效果 https://pan.quark.cn/s/e81b877737c1 Node.js 是一种基于 Chrome V8 引擎的 JavaScript 执行环境,它使开发者能够在服务器端执行 JavaScript 编程,显著促进了全栈开发的应用普及。 在 Node.js 的开发流程中,`node_modules` 文件夹用于存储所有依赖的模块,随着项目的进展,该文件夹可能会变得异常庞大,其中包含了众多可能已不再需要的文件和文件夹,这不仅会消耗大量的硬盘空间,还可能减慢项目的加载时间。 `ModClean 2.0` 正是为了应对这一挑战而设计的工具。 `ModClean` 是一款用于清理 `node_modules` 的软件,其核心功能是移除那些不再被使用的文件和文件夹,从而确保项目的整洁性和运行效率。 `ModClean 2.0` 是此工具的改进版本,在原有功能上增加了更多特性,从而提高了清理工作的效率和精确度。 在 `ModClean 2.0` 中,用户可以设置清理规则,例如排除特定的模块或文件类型,以防止误删重要文件。 该工具通常会保留项目所依赖的核心模块,但会移除测试、文档、示例代码等非运行时必需的部分。 通过这种方式,`ModClean` 能够协助开发者优化项目结构,减少不必要的依赖,加快项目的构建速度。 使用 `ModClean` 的步骤大致如下:1. 需要先安装 `ModClean`,在项目的根目录中执行以下命令: ``` npm install modclean -g ```2. 创建配置文件 `.modcleanrc.json` 或 `.modcleanrc.js`,设定希望清理的规则。 比如,可能需要忽略 `LICENSE` 文件或整个 `docs`...
2026最新微信在线AI客服系统源码 微信客服AI系统是一款基于PHP开发的智能客服解决方案,完美集成企业微信客服,为企业提供7×24小时智能客服服务。系统支持文本对话、图片分析、视频分析等多种交互方式,并具备完善的对话管理、人工转接、咨询提醒等高级功能。 核心功能 ### 1.  智能AI客服 #### 自动回复 - **上下文理解**:系统自动保存用户对话历史,AI能够理解上下文,提供连贯的对话体验 - **个性化配置**:可自定义系统提示词、最大输出长度等AI参数 #### 产品知识库集成 - **公司信息**:支持配置公司简介、官网、竞争对手等信息 - **产品列表**:可添加多个产品,包括产品名称、配置、价格、适用人群、特点等 - **常见问题FAQ**:预设常见问题及答案,AI优先使用知识库内容回答 - **促销活动**:支持配置当前优惠活动,AI会自动向用户推荐 ### 2. 多媒体支持 #### 图片分析 - 支持用户发送图片,AI自动分析图片内容 - 可结合文字描述,提供更精准的分析结果 - 支持常见图片格式:JPG、PNG、GIF、WebP等 #### 视频分析 - 支持用户发送视频,AI自动分析视频内容 - 视频文件自动保存到服务器,提供公网访问 - 支持常见视频格式:MP4、等 ### 3.  人工客服转接 #### 关键词触发 - **自定义关键词**:可配置多个转人工触发关键词(如:人工、客服、转人工等) - **自动转接**:用户消息包含关键词时,自动转接给指定人工客服 - **友好提示**:转接前向用户发送提示消息,提升用户体验 #### 一键介入功能 - **后台管理**:管理员可在对话管理页面查看所有对话记录 - **快速转接**:点击"一键介入"按钮,立即将用户转接给人工客服
全桥LLC谐振变换器,电压电流双环竞争控制策略带说明文档内容概要:本文档主要围绕全桥LLC谐振变换器展开,重点介绍了一种电压电流双环竞争控制策略,并提供了详细的说明文档。该策略结合了拓展移相EPS方法,旨在优化电流应力并支持正反向运行,适用于双有源桥DC-DC变换器的控制。文中通过Simulink进行仿真研究,验证了控制策略的有效性,并利用PLECS工具进行了损耗计算和开环热仿真,确保系统在实际应用中的可靠性和效率。此外,文档还涵盖了DCDC双机并联系统的热管理问题,展示了完整的建模、仿真与分析流程。; 适合人群:具备电力电子、自动化或电气工程背景,熟悉MATLAB/Simulink和PLECS仿真工具,从事电源变换器设计与控制研究的研发人员及高校研究生。; 使用场景及目标:①用于高性能DC-DC变换器的设计与优化,特别是在新能源、电动汽车、储能系统等需要高效能电源转换的场合;②为研究人员提供电压电流双闭环控制、移相控制策略、损耗分析与热仿真的一体化解决方案,提升系统效率与稳定性;③支持正反向功率流动的应用场景,如能量回馈系统。; 阅读建议:建议读者结合Simulink与PLECS仿真模型同步学习,重点关注控制策略的实现逻辑、参数整定方法及热仿真设置,动手复现仿真案例以深入理解系统动态特性与工程实用性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值