InfoQ

新闻

Rails: 用Resource_controller插件给Controllers减肥

作者 Rick DeNatale 译者 贾晓楠 发布于 2008年2月4日 下午8时59分

社区
Ruby
主题
Ruby on Rails,
REST
标签
Rails,
Ruby on Rails,
Rails插件

许多Rails大师提倡的一个导向原则是“丰满的模型,精瘦的控制器”。 Rails控制器只应该包含一些在模型和视图之间周转用的代码。事务逻辑属于模型,而不属于控制器或视图。在如今支持REST的Rails 2.0中,控制器变得非常相象,都包括七个基本的动作(索引、获取、创建、更新、删除、新增和编辑),且具有非常相似的实现方式。在Rails 2.0中,可以简单地用script/generate scaffold standard来建立控制器框架,即生成了一段具有REST特性的控制器代码,如下所示: 

class StandardsController < ApplicationController
  # GET /standards
  # GET /standards.xml
  def index
    @standards = Standard.find(:all)

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @standards }
    end
  end

  # GET /standards/1
  # GET /standards/1.xml
  def show
    @standard = Standard.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @standard }
    end
  end

  # GET /standards/new
  # GET /standards/new.xml
  def new
    @standard = Standard.new

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @standard }
    end
  end

  # GET /standards/1/edit
  def edit
    @standard = Standard.find(params[:id])
  end

  # POST /standards
  # POST /standards.xml
  def create
    @standard = Standard.new(params[:standard])

    respond_to do |format|
      if @standard.save
        flash[:notice] = 'Standard was successfully created.'
        format.html { redirect_to(@standard) }
        format.xml  { render :xml => @standard, :status => :created, :location => @standard }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @standard.errors, :status => :unprocessable_entity }
      end
    end
  end

  # PUT /standards/1
  # PUT /standards/1.xml
  def update
    @standard = Standard.find(params[:id])

    respond_to do |format|
      if @standard.update_attributes(params[:standard])
        flash[:notice] = 'Standard was successfully updated.'
        format.html { redirect_to(@standard) }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @standard.errors, :status => :unprocessable_entity }
      end
    end
  end

  # DELETE /standards/1
  # DELETE /standards/1.xml
  def destroy
    @standard = Standard.find(params[:id])
    @standard.destroy

    respond_to do |format|
      format.html { redirect_to(standards_url) }
      format.xml  { head :ok }
    end
  end
end

除了特别的名字以外,所有自动生成的控制器代码都是这样的。

使用自动生成的控制器非常简单。在许多情况下,很少或者不需要对生成的代码做任何改变,尤其是当你把“精瘦的控制器”这个理念铭记于心时。

另一方面,Ruby/Rails还有一条理念,就是 “不要重复自己(DRY)”。 如果存在几乎重复的代码,即便不是你自己写的,也是违背DRY原则的。

输入:resource_controller。James Golick贡献了一个新的rails插件,称为resource_controller,它可以实现与上面同样的控制器,代码如下:

class StandardsController < ApplicationController
resource_controller
end

然而,这里仍有一个小小的瑕疵。 它没有提供标准的xml响应能力,但可以用一小段代码来实现:

class StandardsController < ApplicationController
  resource_controller

  index.wants.xml   { render :xml => @standards }
  [new, show].each  do |action|
     action.wants.xml   { render :xml => @standard })
  end
  create.wants.xml  { render :xml => @standard, :status => :created, :location => @standard }
  [update, destroy].each do |action|
     action.wants.xml  { head :ok }
  end
  [create_fails, update_fails].each do |action|
     action.wants.xml { render :xml => @standard.errors, :status => :unprocessable_entity }
  end
end

有了这个插件,写控制器代码如同写模型代码一样,只需加上像resource_controller这样的声明的类方法,以及action.wants之类的“回调”。这个插件自动为控制器的每个方法分配实例变量。在上面的代码中,给index方法分配了@standards ,给其他方法分配了@standard。

Rails有一些公用的模式强迫改变控制器代码。其中包括嵌套资源。很容易在config/routes.rb中设置路由:

map.resources :organization, :has_many => :standards

但是,一旦你这样做了,你就需要更改控制器来获取和使用上层资源,并在每个动作中正确使用。resource_controller插件简化了这些。在如上面那样更改路由后,你只需添加一个声明来调用我们的控制器:

class StandardsController < ApplicationController
resource_controller
belongs_to :organization
end

belongs_to声明允许嵌套资源使用控制器。现在,当一个控制器动作通过嵌套资源URL被访问时,例如/organization/1234 /standards,控制器会自动创建一个名为@organization的实例变量,适当地设置好,并使用standards所关联地父对象来查找和 建立Standard模型的实例。

注意, 同样的控制器也工作在非嵌套的URL下,因此我们可以在routes.rb中做另一个映射,来允许在organization之外访问starnards:

map.resources :standard
map.resources :organization, :has_many :standards

这样resource控制器就会自动地工作在这两种上下文中了。

这个插件也处理命名空间控制器、多态嵌套资源(与ActiveRecord多态关联相似和相关)和其他一些奇妙地东西。你也可以获得URL以及工作在请求的URL上下文中的路径辅助函数。

看来Resource_controller是个有用的插件,毫无疑问随着它的成熟,会变得越来越好。细节见James Golicks的博客。另外还有Fabio Akita制作的一段屏幕录像,演示了这个插件的实际使用情况。

查看英文原文:Rails: Resource_controller Plugin Puts Controllers on a Diet

深度内容

和Google互补的搜索引擎Wolfram|Alpha

Wolfram|Alpha与Google究竟是什么关系,Wolfram|Alpha自己是如何定位的?Wolfram|Alaph在多大程度上是语义网搜索呢?InfoQ中文站就等等这些问题采访了Wolfram研究公司中国区商务经理王翔。

SOA契约成熟度模型

本文说明了所推荐的契约版本管理设计策略是如何与SOA成熟度模型发生联系的。文章目的是为实现版本管理和可组合性提供一个路线图。

数据服务简介

Vijay Narayanan在这篇文章中对数据服务的几个方面进行了介绍,它们都是SOA实践者和数据架构师感兴趣的内容。本文对数据服务的几个方面进行了介绍,包括需求定义,基本原理和好处、范围、开发以及消费模式。

分块云计算

在本文中,Jimmy Nilsson描述了一种他在过去数年间观察到的一种正在缓慢成长的架构风格,他把这种风格称为“分块云计算”。

豆瓣网技术架构变迁

罗马不是一天建成的,豆瓣的技术架构也是随着用户规模的增长一直在持续变化中。在本次演讲中,豆瓣的首席架构师洪强宁将与大家一起分享从上线时的单台服务器架构开始一直到现在的豆瓣架构变迁历程。

融合思想:深入探索S#arp架构

Billy McCafferty展示了S#arp架构,它在ASP.NET MVC框架的基础上,荟萃了当今的最佳实践,应用在ASP.NET Web应用程序的架构设计中。

王雷谈开源以及新兴市场计划

中国作为新兴市场中的新兴市场,是Sun在美国之外实施SSE(SUN Startup Essentials)项目重点关注的地区。在QCon Beijing 2009期间,InfoQ中文站有幸对此项目的负责人王雷先生进行了采访,探讨了关于开源、新兴市场、SSE等话题。

使用HTML5构建下一代的Web Form

HTML5 是由 WHATWG发起的,最开始的名称叫做Web Application 1.0,而后这个标准吸纳了Web Forms 2.0的标准,并一同被W3C组织所采用,合并成为下一代的HTML5标准。