`
qiezi
  • 浏览: 492263 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

我对Rails 1.2中 Restful的理解(二)

    博客分类:
  • Ruby
阅读更多
aardvark 写道
最近一直在补Ruby,心里惦记着Rails1.2但是一直没有时间去细看。昨天看了DHH的"Discovering a world of Resources on Rails",再来看楼主这个发帖,发现楼主对这个例子本身的理解有些不完整,对RESTful的理解也有偏差。

楼主的例子看似和DHH的例子很像,但实际很不同。DHH的例子是User/Group,典型的use case是“管理员把某个用户添加到某个组”。这样的例子,从Model到Controller到View恰好是完整的一套,很清晰也很优美。这里User是操作的对象。

而User/Article的例子中,这个User是操作的对象,同时又是操作的主体。一个可能是use case是“用户标记某文章为‘已读’”,但更典型的use case是“当用户阅读某篇文章的同时,标记‘已读’”。这里面同时有两个操作:1)用户阅读文章 2)标记‘已读’(或者说删除‘未读’)。这个例子比User/Group的例子要复杂得多。

其实在DHH的讲演里面提到了这样的例子(恰恰是说“例外”的时候)。我想要在此引用一下DHH的一句话:
引用

CRUD is not a goal,it’s an aspiration,a design technique
CRUD不是一个目标,而是一种精神,一种设计技巧


这句话之后DHH就举了个不用CRUD的例子:Kase。Kase的例子是说,当用户close一个Kase的时候,同时建立一个Closure来保存谁、什么时间关闭了Kase。
当然,这个例子和楼主的例子也是有区别的。楼主的例子里面,阅读一篇文章并不修改文章本身,而关闭一个Kase要修改Kase本身;但是共同点是,都同时涉及到两个Controller。DHH把这种情况当作aspect/view来看:
POST /kases/1;close
POST /identity;aspect

DHH的例子是:
class KasesController < ActionController::Base
  # POST /kases/1;close
  def close
    @kase.close!
    redirect_to :action=>"show"
  end
end

class ClosuresController < ActionController::Base
  def create
    Closure.create!(:kase=>@kase, :closer=>@user
    redirect_to(kase_url(@kase))
  end
end


目前我还不知道Rails1.2中怎样同时用两个Controller。另外我很感兴趣的是,如果这两个Controller做的事需要是transactional的,即或者都成功或者都不成功,rails有没有这样的支持(在一个Controller中当然没有问题,但分散到两个Controller的话rails还能实现transactional吗)。从这个角度来看,我甚至严重怀疑DHH的这个例子是否恰当!

从楼主的代码看,只支持“用户标记某篇文章为‘已读’”,而不能支持用户阅读的同时标记,所以我说这不是个好例子。

看完了DHH那个presentation,我以为Rails1.2的RESTful最闪亮的点是通过ActiveResource提供了漂亮的、简单的系统间(或者系统的不同部分之间)的交互。RESTful绝不仅仅是CRUD,CRUD只是达到RESTful的手段而已。在一般情况下,CRUD精神能简化设计,但CRUD不应得到过分的强调,更不是RESTful的精髓。KasesController::close已经告诉我们"CRUD is everything"这种想法是错误的。
另外,如果在一个系统内部为了RESTful而RESTful,并不能获得RESTful的好处却带来设计及实现上的麻烦,也是不可取的。

谢楼上的思考,我也把"Discovering a world of Resources on Rails"重看了一遍,我认为楼主的做法是正确的,只是他没说清楚一些定义而已。

RESTful核心就是资源,把关系也看作是资源,所以用户加入和退出组可以改成用户与组的关系这个资源的创建和删除。基于这一点我觉得RESTful应该翻译为REST风格,不给它个合适的中文词汇来代替,总是理解起来有些偏差。这一点楼主的例子也是合适的。

你说的Kase那部分实际上DHH提到了3种做法(技巧)[注],而不是说KasesController#close和 ClosuresController#create要分别调用,既然创建了Closure,它里面就包含created_at,这和kase里的 closed_at不是同一个意思吗?何必还更新kase对象呢?所以根本没有事务要考虑,你“甚至严重怀疑DHH的这个例子是否恰当”,我觉得是没理解这个部分。

注:这3种做法,第1种是我们现在用的,scaffold产生的代码就是这种。第2种是把关系转成资源来创建。第3种是用has_one。这3种分别对应到他前面所说的事件、关系、状态。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics