- 浏览: 244660 次
- 性别:
- 来自: 北京
最新评论
-
nowind:
我学ror时使用了haml一个月。现在回到了java,却再也无 ...
HAML必将流行 -
suliangben:
楼主你在幻想吧,你要走出你的幻想世界,接受现实。
HAML必将流行 -
kenrome:
打不开阿嗄
新文章都会发表在 dongbin.org 上,这个 blog 不再更新了 -
Soloara:
haml确实在很多方面体现出了其优势,但不可否认的一点是抽象程 ...
HAML必将流行 -
dayang2001911:
你为什么不把你那边的博文导入到javaeye来呢
新文章都会发表在 dongbin.org 上,这个 blog 不再更新了
读了 http://www.iteye.com/topic/38653,
想从代码方面谈一谈对Rails 1.2中的RESTful application 的感受。
我有User 和 Article两个Model,并且需要某一个User未读的所有Article。我的第一灵感就是声明一个has_and_belongs_to_many(好长的方法啊,每次都怕敲错)。
很简单是吧,那么Controller怎么写呢?
等一下,我这么写行不行呢?
这两种写法哪一个好呢?我踌躇,我犹豫,我翻来覆去睡不着觉。
... ...
如果把HTTP之上的所有请求都看成资源的操作的话。add_fresh_reader操作什么资源呢?提这个问题的同时,一个新model浮现了出来:Unreaded 。
又见到似曾相识的"create", "destroy"。 如果使用资源的方式思考,我们就会发现,CRUD is everything!
Constraints is Freedom
CRUD 形成了一种约束,把我们从权衡Controller和action风格这种无聊的事情中解脱出来,按照统一的风格来编写程序以及构造URL。使我们有精力关注更重要的事。
REST还避免我们编写大的Controller。可曾有人后悔曾经写过的包含十几个action的,并且action之间毫无联系的Controller呢? 其实大部分情况下,一个Controller有7个action就够了,并且这些action关注于同一Model,大大提高了正交性.
还有什么好处,欢迎大家补充。
Faint, 俺是东北人,俺们那尬搭都是活雷锋。
哎呀妈呀,可算找到亲银了,抱一下 你是东北哪嘎达的?
没错,在show里面是可以做Unreaded的更新。但是那样的话,不恰恰违背了他搞出来一个Unreaded的初衷吗?另外一点,在ArticlesController::show里面加了对unreaded的更新,不还破坏了CRUD的一致性吗?
我觉得这算是个特殊的需求吧,就好像某用户浏览过某圈子,就设置一个状态表明他浏览过,无论在show里面怎么做,都违背了show的原意这与Unreaded本身没什么关系。我感觉这类问题还是要分开解释。show是一个GET动作,用来获取一个资源,Unreaded(或者改成Readed?)对象的创建是一个附加的隐藏动作,这个动作和show这个动作本身是密不可分的,而不是和其它什么资源,所以不宜分开。这也是为什么RESTful是用在controller而不是model,如果实际动作和model的CRUD这么吻合,干脆就直接把RESTful和model联系起来,去掉controller算了。
RESTful的确有些难以解释,用简单的东西去描述复杂的逻辑,总会有些碰撞,这也是讨论的原因。我最近看到的讨论来看,大部分人和我一样对这个概念还是有些模糊,希望多多讨论,理清这个概念。
我对这方面的争论有点失去耐心了,最后说一下。
上面已经说得很清楚,你非要把这2个扯到一块不知道有什么意义,任何情况下我们只需要其中一种做法,你要2种都用也可以,但在一个action里的一个事务内就可以完成了,不存在多个action完成同一个数据库事务,你见过这种实现吗?
2)再说楼主的例子
假设说一个用户要阅读一篇文章,你是不是应该去调ArticlesController::show呢?那么Unreaded怎么得到更新?
show里面可以处理Unreaded更新,代码就不用演示了吧。/articles/1/unreaded里面也可以处理,这是2种不同的做法。
从上面你发的这些内容,我觉得在RESTful面前,你把model和controller混在一起了。
我仔细看了一遍,清楚了。原来他从28页的Kase到30页的Closure已经换了一种做法。因为两边的代码都不完整,放在一起倒像是完整的,就被误导了。这不,前面是Kase, KasesController,后面是Closure, ClosuresController,放一块儿就全了嘛(汗!)
Model和Controller我还是分得清楚的。你大概是看我把Kase和ClosuresController并列才这么说,但我完全是从他的代码出发。他的save!写在Kase里,create!写在ClosuresController里,我也只好这样列举。
OK,回到楼主的例子。
没错,在show里面是可以做Unreaded的更新。但是那样的话,不恰恰违背了他搞出来一个Unreaded的初衷吗?另外一点,在ArticlesController::show里面加了对unreaded的更新,不还破坏了CRUD的一致性吗?
我对这方面的争论有点失去耐心了,最后说一下。
上面已经说得很清楚,你非要把这2个扯到一块不知道有什么意义,任何情况下我们只需要其中一种做法,你要2种都用也可以,但在一个action里的一个事务内就可以完成了,不存在多个action完成同一个数据库事务,你见过这种实现吗?
2)再说楼主的例子
假设说一个用户要阅读一篇文章,你是不是应该去调ArticlesController::show呢?那么Unreaded怎么得到更新?
show里面可以处理Unreaded更新,代码就不用演示了吧。/articles/1/unreaded里面也可以处理,这是2种不同的做法。
从上面你发的这些内容,我觉得在RESTful面前,你把model和controller混在一起了。
我对DHH怎么做那一部分确实不太理解,但你的解释就让我更疑惑了。从他的代码看,closed_at确实是在kases表中,而在closures表中有没有created_at却并不明确。另外,kases表中还有个closed要更新:
这怎么都是两条SQL的事,怎么可能没有事务要考虑呢?虽然说ActiveRecord有built-in transaction,但好像不适用这种情况吧。
那是3种不同的做法:
第一种是修改记录,同时修改closed和closed_at。
第二种是创建一个Closure对象,是不是有created_at无关紧要,如果你需要closed_at就加上created_at来代替它,不需要说明。是否已经closed可以通过kase的关联来查询到,所以不需要更新kase,否则用这种关联方式岂不是降低效率还自讨苦吃?
第三种是多次创建Progress,但只有最后一个是有效的,用不同的记录来显示状态。
这三种也就是他说的“技巧”,之间没有关联,如果一件事还要请求2次,当然是不合理的。
Please READ!
Please READ!
我没看出来哪有2条SQL,既然都不用请求2次,难道是这里有2条SQL?
只有一个更新要什么事务?
我上面已经说了,我认为这3种之间毫无关联,如果你非要认为第1种和第2种有什么关联,那你解释一下第3种和前2种有什么关系吧,它们放在一起并没有什么不一样。
我对DHH怎么做那一部分确实不太理解,但你的解释就让我更疑惑了。从他的代码看,closed_at确实是在kases表中,而在closures表中有没有created_at却并不明确。另外,kases表中还有个closed要更新:
这怎么都是两条SQL的事,怎么可能没有事务要考虑呢?虽然说ActiveRecord有built-in transaction,但好像不适用这种情况吧。
那是3种不同的做法:
第一种是修改记录,同时修改closed和closed_at。
第二种是创建一个Closure对象,是不是有created_at无关紧要,如果你需要closed_at就加上created_at来代替它,不需要说明。是否已经closed可以通过kase的关联来查询到,所以不需要更新kase,否则用这种关联方式岂不是降低效率还自讨苦吃?
第三种是多次创建Progress,但只有最后一个是有效的,用不同的记录来显示状态。
这三种也就是他说的“技巧”,之间没有关联,如果一件事还要请求2次,当然是不合理的。
Please READ!
我对DHH怎么做那一部分确实不太理解,但你的解释就让我更疑惑了。从他的代码看,closed_at确实是在kases表中,而在closures表中有没有created_at却并不明确。另外,kases表中还有个closed要更新:
这怎么都是两条SQL的事,怎么可能没有事务要考虑呢?虽然说ActiveRecord有built-in transaction,但好像不适用这种情况吧。
那是3种不同的做法:
第一种是修改记录,同时修改closed和closed_at。
第二种是创建一个Closure对象,是不是有created_at无关紧要,如果你需要closed_at就加上created_at来代替它,不需要说明。是否已经closed可以通过kase的关联来查询到,所以不需要更新kase,否则用这种关联方式岂不是降低效率还自讨苦吃?
第三种是多次创建Progress,但只有最后一个是有效的,用不同的记录来显示状态。
这三种也就是他说的“技巧”,之间没有关联,如果一件事还要请求2次,当然是不合理的。
谢楼上的思考,我也把"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种分别对应到他前面所说的事件、关系、状态。
我对DHH怎么做那一部分确实不太理解,但你的解释就让我更疑惑了。从他的代码看,closed_at确实是在kases表中,而在closures表中有没有created_at却并不明确。另外,kases表中还有个closed要更新:
这怎么都是两条SQL的事,怎么可能没有事务要考虑呢?虽然说ActiveRecord有built-in transaction,但好像不适用这种情况吧。
谢楼上的思考,我也把"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种分别对应到他前面所说的事件、关系、状态。
根据session里面的用户来决定,管理员和普通用户的页面跳转当然不一样。
我进来在想restful形式的分页的时候就觉得,不符合restful的页面应该以AJAX方式呈现。
Faint, 俺是东北人,俺们那尬搭都是活雷锋。
想从代码方面谈一谈对Rails 1.2中的RESTful application 的感受。
我有User 和 Article两个Model,并且需要某一个User未读的所有Article。我的第一灵感就是声明一个has_and_belongs_to_many(好长的方法啊,每次都怕敲错)。
class User < ActiveRecord::Base has_and_belongs_to_many :articles end class Article < ActiveRecord::Base has_and_belongs_to_many :users end
很简单是吧,那么Controller怎么写呢?
class UsersController < ApplicationController def add_unreaded @user.articles << @article end def remove_unreaded @user.articles.delete @article end end
等一下,我这么写行不行呢?
class ArticlesController < ApplicationController def add_fresh_reader @article.users << @user end def remove_fresh_reader @article.users.delete @user end end
这两种写法哪一个好呢?我踌躇,我犹豫,我翻来覆去睡不着觉。
... ...
如果把HTTP之上的所有请求都看成资源的操作的话。add_fresh_reader操作什么资源呢?提这个问题的同时,一个新model浮现了出来:Unreaded 。
class User < ActiveRecord::Base has_many :articles, :through => :unreadeds end class Article < ActiveRecord::Base has_many :users,:through => :unreadeds end class Unreaded < ActiveRecord::Base end class UnreadedsController < ApplicationController def create @unreaded = Unreaded.create(params[:unreaded]) end def destroy @unreaded = Unreaded.find(params[:id]) @unreaded.destroy end end
又见到似曾相识的"create", "destroy"。 如果使用资源的方式思考,我们就会发现,CRUD is everything!
Constraints is Freedom
CRUD 形成了一种约束,把我们从权衡Controller和action风格这种无聊的事情中解脱出来,按照统一的风格来编写程序以及构造URL。使我们有精力关注更重要的事。
REST还避免我们编写大的Controller。可曾有人后悔曾经写过的包含十几个action的,并且action之间毫无联系的Controller呢? 其实大部分情况下,一个Controller有7个action就够了,并且这些action关注于同一Model,大大提高了正交性.
还有什么好处,欢迎大家补充。
评论
26 楼
chen823
2007-09-15
25 楼
曼陀罗
2006-12-30
dongbin 写道
cbmyfirst 写道
dongbin 写道
多谢指点,其实我这个例子是我项目代码的一部分,直接搬过来了,所以表达效果没有你说的那一篇好。
其实讲得最好的还是DHH的演讲,别的什么都不用看了。
dongbin是台湾的兄弟吗,能否介绍几个有关rails或java的台湾论坛,先谢其实讲得最好的还是DHH的演讲,别的什么都不用看了。
哎呀妈呀,可算找到亲银了,抱一下 你是东北哪嘎达的?
24 楼
李超群
2006-12-21
站出来说两句。先说楼主的例子。个人感觉可以用Restful实现。restful强调的是资源,即把关系提炼出来成更高的东西。
另外,DHH举的这个例子是说CRUD并不是一切。原因呢,用了Kase这个例子。其意思是说我们现在要 关闭这个Kase,但因为我们要保存一些历史数据,所以我们不能删除它,所以只能close.而这个Close就是不能用CRUD表达的。
仔细看录像。讲解得很清楚。
另外,DHH举的这个例子是说CRUD并不是一切。原因呢,用了Kase这个例子。其意思是说我们现在要 关闭这个Kase,但因为我们要保存一些历史数据,所以我们不能删除它,所以只能close.而这个Close就是不能用CRUD表达的。
仔细看录像。讲解得很清楚。
23 楼
fixopen
2006-12-18
浏览过或者没有浏览过,不应该影响资源本身,那应该仅仅是资源和人的关系的一种变化,我觉得这儿考虑做个两者之外的一个记录或者日志,当然,通过改变path来做日志不是不行,只是不好而已。应该肯定有更好的方式。
22 楼
qiezi
2006-12-16
aardvark 写道
没错,在show里面是可以做Unreaded的更新。但是那样的话,不恰恰违背了他搞出来一个Unreaded的初衷吗?另外一点,在ArticlesController::show里面加了对unreaded的更新,不还破坏了CRUD的一致性吗?
我觉得这算是个特殊的需求吧,就好像某用户浏览过某圈子,就设置一个状态表明他浏览过,无论在show里面怎么做,都违背了show的原意这与Unreaded本身没什么关系。我感觉这类问题还是要分开解释。show是一个GET动作,用来获取一个资源,Unreaded(或者改成Readed?)对象的创建是一个附加的隐藏动作,这个动作和show这个动作本身是密不可分的,而不是和其它什么资源,所以不宜分开。这也是为什么RESTful是用在controller而不是model,如果实际动作和model的CRUD这么吻合,干脆就直接把RESTful和model联系起来,去掉controller算了。
RESTful的确有些难以解释,用简单的东西去描述复杂的逻辑,总会有些碰撞,这也是讨论的原因。我最近看到的讨论来看,大部分人和我一样对这个概念还是有些模糊,希望多多讨论,理清这个概念。
21 楼
aardvark
2006-12-16
qiezi 写道
aardvark 写道
1)先说David的代码
不想再paste一遍了,请看Kase::close!,这里难道不是要更新kases表中的一个row吗?
再看ClosuresController::create,这里难道不是要在closures中创建一个row吗?
这不是两条SQL是什么?
不想再paste一遍了,请看Kase::close!,这里难道不是要更新kases表中的一个row吗?
再看ClosuresController::create,这里难道不是要在closures中创建一个row吗?
这不是两条SQL是什么?
我对这方面的争论有点失去耐心了,最后说一下。
上面已经说得很清楚,你非要把这2个扯到一块不知道有什么意义,任何情况下我们只需要其中一种做法,你要2种都用也可以,但在一个action里的一个事务内就可以完成了,不存在多个action完成同一个数据库事务,你见过这种实现吗?
aardvark 写道
2)再说楼主的例子
假设说一个用户要阅读一篇文章,你是不是应该去调ArticlesController::show呢?那么Unreaded怎么得到更新?
show里面可以处理Unreaded更新,代码就不用演示了吧。/articles/1/unreaded里面也可以处理,这是2种不同的做法。
从上面你发的这些内容,我觉得在RESTful面前,你把model和controller混在一起了。
我仔细看了一遍,清楚了。原来他从28页的Kase到30页的Closure已经换了一种做法。因为两边的代码都不完整,放在一起倒像是完整的,就被误导了。这不,前面是Kase, KasesController,后面是Closure, ClosuresController,放一块儿就全了嘛(汗!)
Model和Controller我还是分得清楚的。你大概是看我把Kase和ClosuresController并列才这么说,但我完全是从他的代码出发。他的save!写在Kase里,create!写在ClosuresController里,我也只好这样列举。
OK,回到楼主的例子。
没错,在show里面是可以做Unreaded的更新。但是那样的话,不恰恰违背了他搞出来一个Unreaded的初衷吗?另外一点,在ArticlesController::show里面加了对unreaded的更新,不还破坏了CRUD的一致性吗?
20 楼
qiezi
2006-12-16
aardvark 写道
1)先说David的代码
不想再paste一遍了,请看Kase::close!,这里难道不是要更新kases表中的一个row吗?
再看ClosuresController::create,这里难道不是要在closures中创建一个row吗?
这不是两条SQL是什么?
不想再paste一遍了,请看Kase::close!,这里难道不是要更新kases表中的一个row吗?
再看ClosuresController::create,这里难道不是要在closures中创建一个row吗?
这不是两条SQL是什么?
我对这方面的争论有点失去耐心了,最后说一下。
上面已经说得很清楚,你非要把这2个扯到一块不知道有什么意义,任何情况下我们只需要其中一种做法,你要2种都用也可以,但在一个action里的一个事务内就可以完成了,不存在多个action完成同一个数据库事务,你见过这种实现吗?
aardvark 写道
2)再说楼主的例子
假设说一个用户要阅读一篇文章,你是不是应该去调ArticlesController::show呢?那么Unreaded怎么得到更新?
show里面可以处理Unreaded更新,代码就不用演示了吧。/articles/1/unreaded里面也可以处理,这是2种不同的做法。
从上面你发的这些内容,我觉得在RESTful面前,你把model和controller混在一起了。
19 楼
aardvark
2006-12-16
1)先说David的代码
不想再paste一遍了,请看Kase::close!,这里难道不是要更新kases表中的一个row吗?
再看ClosuresController::create,这里难道不是要在closures中创建一个row吗?
这不是两条SQL是什么?
2)再说楼主的例子
假设说一个用户要阅读一篇文章,你是不是应该去调ArticlesController::show呢?那么Unreaded怎么得到更新?
不想再paste一遍了,请看Kase::close!,这里难道不是要更新kases表中的一个row吗?
再看ClosuresController::create,这里难道不是要在closures中创建一个row吗?
这不是两条SQL是什么?
2)再说楼主的例子
假设说一个用户要阅读一篇文章,你是不是应该去调ArticlesController::show呢?那么Unreaded怎么得到更新?
18 楼
qiezi
2006-12-16
aardvark 写道
qiezi 写道
aardvark 写道
我对DHH怎么做那一部分确实不太理解,但你的解释就让我更疑惑了。从他的代码看,closed_at确实是在kases表中,而在closures表中有没有created_at却并不明确。另外,kases表中还有个closed要更新:
class Kase < ActiveRecord::Base def close!(at = Time.now) self.closed_at = at self.closed = true save! end end
这怎么都是两条SQL的事,怎么可能没有事务要考虑呢?虽然说ActiveRecord有built-in transaction,但好像不适用这种情况吧。
那是3种不同的做法:
第一种是修改记录,同时修改closed和closed_at。
第二种是创建一个Closure对象,是不是有created_at无关紧要,如果你需要closed_at就加上created_at来代替它,不需要说明。是否已经closed可以通过kase的关联来查询到,所以不需要更新kase,否则用这种关联方式岂不是降低效率还自讨苦吃?
第三种是多次创建Progress,但只有最后一个是有效的,用不同的记录来显示状态。
这三种也就是他说的“技巧”,之间没有关联,如果一件事还要请求2次,当然是不合理的。
Please READ!
Please READ!
我没看出来哪有2条SQL,既然都不用请求2次,难道是这里有2条SQL?
class Kase < ActiveRecord::Base def close!(at = Time.now) self.closed_at = at self.closed = true save! end end
只有一个更新要什么事务?
我上面已经说了,我认为这3种之间毫无关联,如果你非要认为第1种和第2种有什么关联,那你解释一下第3种和前2种有什么关系吧,它们放在一起并没有什么不一样。
17 楼
aardvark
2006-12-16
qiezi 写道
aardvark 写道
我对DHH怎么做那一部分确实不太理解,但你的解释就让我更疑惑了。从他的代码看,closed_at确实是在kases表中,而在closures表中有没有created_at却并不明确。另外,kases表中还有个closed要更新:
class Kase < ActiveRecord::Base def close!(at = Time.now) self.closed_at = at self.closed = true save! end end
这怎么都是两条SQL的事,怎么可能没有事务要考虑呢?虽然说ActiveRecord有built-in transaction,但好像不适用这种情况吧。
那是3种不同的做法:
第一种是修改记录,同时修改closed和closed_at。
第二种是创建一个Closure对象,是不是有created_at无关紧要,如果你需要closed_at就加上created_at来代替它,不需要说明。是否已经closed可以通过kase的关联来查询到,所以不需要更新kase,否则用这种关联方式岂不是降低效率还自讨苦吃?
第三种是多次创建Progress,但只有最后一个是有效的,用不同的记录来显示状态。
这三种也就是他说的“技巧”,之间没有关联,如果一件事还要请求2次,当然是不合理的。
Please READ!
16 楼
qiezi
2006-12-16
aardvark 写道
我对DHH怎么做那一部分确实不太理解,但你的解释就让我更疑惑了。从他的代码看,closed_at确实是在kases表中,而在closures表中有没有created_at却并不明确。另外,kases表中还有个closed要更新:
class Kase < ActiveRecord::Base def close!(at = Time.now) self.closed_at = at self.closed = true save! end end
这怎么都是两条SQL的事,怎么可能没有事务要考虑呢?虽然说ActiveRecord有built-in transaction,但好像不适用这种情况吧。
那是3种不同的做法:
第一种是修改记录,同时修改closed和closed_at。
第二种是创建一个Closure对象,是不是有created_at无关紧要,如果你需要closed_at就加上created_at来代替它,不需要说明。是否已经closed可以通过kase的关联来查询到,所以不需要更新kase,否则用这种关联方式岂不是降低效率还自讨苦吃?
第三种是多次创建Progress,但只有最后一个是有效的,用不同的记录来显示状态。
这三种也就是他说的“技巧”,之间没有关联,如果一件事还要请求2次,当然是不合理的。
15 楼
aardvark
2006-12-16
qiezi 写道
谢楼上的思考,我也把"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种分别对应到他前面所说的事件、关系、状态。
我对DHH怎么做那一部分确实不太理解,但你的解释就让我更疑惑了。从他的代码看,closed_at确实是在kases表中,而在closures表中有没有created_at却并不明确。另外,kases表中还有个closed要更新:
class Kase < ActiveRecord::Base def close!(at = Time.now) self.closed_at = at self.closed = true save! end end
这怎么都是两条SQL的事,怎么可能没有事务要考虑呢?虽然说ActiveRecord有built-in transaction,但好像不适用这种情况吧。
14 楼
qiezi
2006-12-16
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的例子是:
目前我还不知道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的好处却带来设计及实现上的麻烦,也是不可取的。
楼主的例子看似和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种分别对应到他前面所说的事件、关系、状态。
13 楼
aardvark
2006-12-16
最近一直在补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的例子是:
目前我还不知道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的好处却带来设计及实现上的麻烦,也是不可取的。
楼主的例子看似和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的好处却带来设计及实现上的麻烦,也是不可取的。
12 楼
dongbin
2006-12-15
qiezi 写道
讨论:
我总觉得REST应该用于提供数据而不是页面,还是用用户和圈子作例子吧,感觉顺畅一些。
比如某个用户的页面,他选一个圈子,点击“加入”就加入了这个圈子;而圈子的管理员也可以选择用户,并点击“添加”把用户加入圈子。
这里2个页面完成的是同一个操作,都是创建一个用户-圈子的关系,但操作完以后的页面转向会不同。如果用REST来提供页面,如何来处理这些转向?另加参数?那不是搞复杂了嘛。
所以我觉得应该是浏览器上通过AJAX请求这个action,返回数据,浏览器脚本把数据处理成显示,这也是AJAX最适合的方式。
如果只提供数据,实际上不需要7种action,4种就可以了:
new和edit都是提供页面的。
我总觉得REST应该用于提供数据而不是页面,还是用用户和圈子作例子吧,感觉顺畅一些。
比如某个用户的页面,他选一个圈子,点击“加入”就加入了这个圈子;而圈子的管理员也可以选择用户,并点击“添加”把用户加入圈子。
这里2个页面完成的是同一个操作,都是创建一个用户-圈子的关系,但操作完以后的页面转向会不同。如果用REST来提供页面,如何来处理这些转向?另加参数?那不是搞复杂了嘛。
所以我觉得应该是浏览器上通过AJAX请求这个action,返回数据,浏览器脚本把数据处理成显示,这也是AJAX最适合的方式。
如果只提供数据,实际上不需要7种action,4种就可以了:
GET /posts => /posts/index GET /posts/1 => /posts/index/1 PUT /posts/1 => /posts/update/1 POST /posts => /posts/create DELETE /posts/1 => /posts/destroy/1
new和edit都是提供页面的。
根据session里面的用户来决定,管理员和普通用户的页面跳转当然不一样。
11 楼
花花公子
2006-12-15
qiezi 写道
讨论:
所以我觉得应该是浏览器上通过AJAX请求这个action,返回数据,浏览器脚本把数据处理成显示,这也是AJAX最适合的方式。
new和edit都是提供页面的。
所以我觉得应该是浏览器上通过AJAX请求这个action,返回数据,浏览器脚本把数据处理成显示,这也是AJAX最适合的方式。
new和edit都是提供页面的。
我进来在想restful形式的分页的时候就觉得,不符合restful的页面应该以AJAX方式呈现。
10 楼
qiezi
2006-12-15
讨论:
我总觉得REST应该用于提供数据而不是页面,还是用用户和圈子作例子吧,感觉顺畅一些。
比如某个用户的页面,他选一个圈子,点击“加入”就加入了这个圈子;而圈子的管理员也可以选择用户,并点击“添加”把用户加入圈子。
这里2个页面完成的是同一个操作,都是创建一个用户-圈子的关系,但操作完以后的页面转向会不同。如果用REST来提供页面,如何来处理这些转向?另加参数?那不是搞复杂了嘛。
所以我觉得应该是浏览器上通过AJAX请求这个action,返回数据,浏览器脚本把数据处理成显示,这也是AJAX最适合的方式。
如果只提供数据,实际上不需要7种action,4种就可以了:
new和edit都是提供页面的。
我总觉得REST应该用于提供数据而不是页面,还是用用户和圈子作例子吧,感觉顺畅一些。
比如某个用户的页面,他选一个圈子,点击“加入”就加入了这个圈子;而圈子的管理员也可以选择用户,并点击“添加”把用户加入圈子。
这里2个页面完成的是同一个操作,都是创建一个用户-圈子的关系,但操作完以后的页面转向会不同。如果用REST来提供页面,如何来处理这些转向?另加参数?那不是搞复杂了嘛。
所以我觉得应该是浏览器上通过AJAX请求这个action,返回数据,浏览器脚本把数据处理成显示,这也是AJAX最适合的方式。
如果只提供数据,实际上不需要7种action,4种就可以了:
GET /posts => /posts/index GET /posts/1 => /posts/index/1 PUT /posts/1 => /posts/update/1 POST /posts => /posts/create DELETE /posts/1 => /posts/destroy/1
new和edit都是提供页面的。
9 楼
dongbin
2006-12-14
cbmyfirst 写道
dongbin 写道
多谢指点,其实我这个例子是我项目代码的一部分,直接搬过来了,所以表达效果没有你说的那一篇好。
其实讲得最好的还是DHH的演讲,别的什么都不用看了。
dongbin是台湾的兄弟吗,能否介绍几个有关rails或java的台湾论坛,先谢其实讲得最好的还是DHH的演讲,别的什么都不用看了。
8 楼
cbmyfirst
2006-12-14
dongbin 写道
多谢指点,其实我这个例子是我项目代码的一部分,直接搬过来了,所以表达效果没有你说的那一篇好。
其实讲得最好的还是DHH的演讲,别的什么都不用看了。
dongbin是台湾的兄弟吗,能否介绍几个有关rails或java的台湾论坛,先谢其实讲得最好的还是DHH的演讲,别的什么都不用看了。
7 楼
dongbin
2006-12-14
多谢指点,其实我这个例子是我项目代码的一部分,直接搬过来了,所以表达效果没有你说的那一篇好。
其实讲得最好的还是DHH的演讲,别的什么都不用看了。
其实讲得最好的还是DHH的演讲,别的什么都不用看了。
发表评论
-
什么是Ruby之道?
2007-10-07 10:27 2880什么是Ruby之道? 翻译这篇文章让我对这个问题有了更深的理解 ... -
如何让CruiseControlrb生成RSpec 的rcov报告
2007-09-10 15:01 1736desc "Run all specs in spe ... -
REST 是什么?
2007-07-27 11:17 17228开发过程中,在三个Model的REST描述上,我昨天冥思苦想了 ... -
Matrix Test 的 Rspec实现 -- matrix_spec
2007-07-25 18:32 1577ZenTest的作者提出了Matrix Test ,并且在Ze ... -
map.resources在edge rails中的变化
2007-06-30 17:22 1814map.resources :account_types, ... -
如何测试subdomain
2007-06-30 16:18 1563Mock 一下Request. module Actio ... -
test_helpful released -- A plugin on rails to make test easier
2007-06-22 10:22 1503I extract the plugin from a rea ... -
最近的学习内容
2007-06-20 10:44 1341CSS网页谁都会编,如何用最少的HTML和CSS进行布局就很少 ... -
make_resourceful 0.1.0 released
2007-05-27 01:33 1568make_resourceful 0.1.0 released ... -
Peercode的Rails视频太精彩了
2007-05-24 01:44 3077人外有人,天外有天。昨天把Peercode的视频看了一遍,真是 ... -
把Restful的潜能发掘到极限
2007-05-21 07:20 1285http://www.hamptoncatlin.com/as ... -
heckle--测试覆盖率检测工具
2007-05-19 23:32 1634上次rails爱好者聚会时,跟Robbin Lu讨论过测试覆盖 ... -
我的gem 列表
2007-05-19 23:12 2470看到 秀出你的Gem我也秀一下。 actionpack (1 ... -
HAML必将流行
2007-05-19 14:06 4928不管你认不认同HAML,它正在获得关注。可以预料的是,一场口水 ... -
SASS是一个好东西
2007-05-18 11:45 2115HAML 1.5以后的新特性要数sass最为吸引人了。昨天试用 ... -
想不通为什么是JRuby
2007-05-13 10:29 1813ThoughtWorks大力宣传JRuby,可是我是在想不通原 ... -
刚刚发现的edge rails中的几个变化
2007-05-06 21:03 2613今天把一个程序切换到edge rails(revision=6 ... -
我的 .emacs 文件
2007-05-02 20:00 4900(custom-set-variables ;; c ... -
Rails聚会小记
2007-04-09 01:54 2807这次聚会的目的虽然说 ... -
使用Ruby实现算法时遇到的性能问题
2006-01-13 03:15 1449昨天作了一道Topcoder的 ...
相关推荐
### RestFul_Rails_Dev_v_0.1 关键知识点解析 #### 1. REST 概念与背景 REST(Representational State Transfer)是一种...在 Rails 中实现 RESTful 开发不仅可以提高开发效率,还能确保应用程序的一致性和可扩展性。
【RESTful Rails Development】 REST,全称为Representational State Transfer,是一种基于HTTP协议的设计原则,由Roy Fielding在其博士论文中提出。REST的核心思想是利用HTTP的GET、POST、PUT、DELETE等方法来操作...
- **RESTful路由**:对RESTful路由进行了改进,使其更加符合REST原则,同时也更加易于理解和维护。 ##### 3.6 异常处理 - **异常处理**:Rails 2.0引入了`rescue_from`机制,允许开发者更优雅地处理异常,并可以...
Ruby on Rails自版本1.2起就内置了对REST的支持,这极大地简化了Web应用的开发过程。 - **RESTful路由**:通过定义路由,可以自动地为不同的HTTP动词映射到相应的控制器动作。 - **资源控制器**:每个资源都对应一...
根据提供的标题、描述以及部分内容,我们可以清晰地了解到这段文本记录了一次安装Ruby on Rails及其...对于开发者来说,理解这些依赖库的工作原理及其如何集成到Rails中是非常重要的,这有助于更高效地进行Web开发。
Ruby on Rails是遵循REST原则的开源Web开发框架,自1.2版本起,RESTful设计成为了其核心理念。Rails框架通过约定优于配置(Convention over Configuration)的原则,使得开发者能快速构建RESTful应用。本项目将运用...
Ruby作为一种面向对象的、动态且强大的编程语言,因其简洁的语法和丰富的库支持,在Web开发领域尤其是Ruby on Rails框架中有着广泛的应用。 一、Ruby基础 1.1 Ruby介绍:学习Ruby的历史、特点以及它在软件开发中的...
Rails利用REST软件架构思想对网络服务也提供了一流的支持。从最直观的角度看待REST,它是网络服务最理想的手段,但是Rails框架把REST带到了网络应用软件开发框架。这是一次飞跃,让REST的思想从网络服务的应用提升到...
RESTful API设计原则要求API清晰、直观、易于理解。在本系统中,我们遵循以下规则: - 使用标准HTTP方法:GET用于检索信息,POST用于创建信息,PUT用于更新信息,DELETE用于删除信息。 - URL命名简洁明确,使用名词...
- **RESTful 路由**:支持 RESTful 设计风格的 URL 结构。 **5.3 ActiveRecord** - **模型定义**:定义数据库表对应的类。 - **数据库迁移**:用于修改数据库结构的脚本。 - **关联**:定义模型之间的关系,如 `...