经过断断续续几个月的学习,Rails 终于毕业啦,非常开心!! 当然,我说的毕业,也就是一般大学生毕业的水平,大概怎么样,你懂的。但是至少,自己目前已经进入一个非常好的循环,简单点说:从一个仅仅懂 Ruby 的程序员,成长为一个懂 Ruby 的初级 Rails 程序员。
本贴也算是本人对于咱社区 Rails 版块,有关技术分享的第一帖!! 同时,这又是一个对自己学习 Rails 的又一个阶段性总结
.
P.S. 刚开始学 Rails 那会儿有写过一篇 使用Rails的阶段性总结
(链接:http://ruby-china.org/topics/2581)
来 Ruby-china 都快半年啦!这是这么久,我都一直没有机会在 Rails 版块分享自己的经验。主要因为自己对于 Rails 一直处在小白的阶段。直到最近,通过练手,尝试独立完成了几个很小的项目,才感觉到本人的 Rails 水平终于算是毕业啦!! 因为我本人经历了从一个完全不懂web开发的初学者
到对于Rails的很多实现方式有了自己的理解
的过程,再加上自己反复的 学习归纳,跳进一个坑,然后爬出来,再重新学习归纳 的实践,所以也总结出来一些使用 Rails 的心得体会。也正因为如此,我觉得对于刚刚接触 Rails 的新人,一定要仔细看本贴,因为这绝对会让你少走很多的弯路!!
也欢迎社区的各位兄弟们踊跃拍砖,有理解不对的对方,一定要不吝批评指正!!!
我打算经过以下几个部分来总结我的学习经验:
以目前本人的经验来说,Rails 和 Ruby 的关系,远没有想象中的那么大。我可以毫不夸张地说:即使没有太多的Ruby经验, 你完全可以成为一个很好的Rails程序员
, 在这点上我深有体会。不瞒大家说,在这段时间的 Rails 学习中,_我感觉我的 Ruby 水平不但没有进步,反而绝对是退步了, 因为作为一个初级Rails的程序员
, 实在是用不到太多的 Ruby 知识。
我上面这样讲,可能会对新人有个误导,我不学 Ruby 就可以开始 Rails, 其实还是要学的。但是初期完全没必要太深入。我顺便总结下成为一个很好的Rails程序员可能会面对的Ruby知识
. 除非你要对 Rails 框架进行大的改动,或写一些 gem, 否则下面这些绝对够用了。
会用 if, unless, 以及迭代器 (循环很少被使用). 我 Rails 经验尚少,不过实际编码中,简单的逻辑判断在编码中占大多数。
了解 Ruby 中的一些特殊的命名惯例,哈希 (hash) 的定义,符号 (symbol) 的含义,
Ruby 中方法的定义,类的定义,方法的可见性含义。其中要特别注意的是:Rails 中实例变量的特殊意义(稍后会讲)
以及 Ruby 中self
的含义。说实在,如果能对于 Ruby 中的 self 理解透彻,那你 Ruby 就很靠谱了, 但是如果你仅凭 rails 来开发 web 应用,就希望了解 Ruby 中的 self, 貌似不可能呀!!
模块混入,类的继承关系含义,如果不懂这个,遇到一个 gem, 它是如何加入到你 Rails 环境中,你可能会很困扰。
block 的使用以及定义。貌似大多数情况下,都仅仅是在使用 block, 只有在定义 view 中的 helper 方法或 Model 中的 scope 时,才会用到 block.
会使用基本的正则表达式。
暂时先想起了这些,其他的等我想到了再补充吧。
首先,我还是想老生常谈似的,把之前的老话重提一下:Rails 不是给新人用的玩意儿。
如果你打算在 Rails 开发方面有所建树的话,这是我所建议的基础知识的优先级
:
基本的HTML以及CSS一定要会看, 而且会写!!
, 这一步不过关,你甚至都无法在编码的初期展现一个 outline 出来,下一步很难正确的进行下去,在这点上我曾经有有过血淋淋的教训,切记切记。
要懂 SQL. 我指的不仅仅是 ORM, 包括完整的 SQL 查询。其实 SQL 没有想象的那么难。而且 Rails3 针对所有的 active 的查询,都会在终端下输出对应的 SQL, 这绝对是一个学习 SQL 的好机会,相信我,仅凭 ORM, 而不了解 SQL, 你其实不可能总是理清表之间的关系. 这点我也是深有体会呀,不过是正面的。:-)
真正的
理解 Rails 的 RESTful 路由机制,以及命名路由
, 稍后我会详细讨论。
懂得基本的 Ruby 语法,不要觉得意外,这绝对是最低优先级
最坑爹,最大的陷阱,就是对于 RESTful 方式的路由的理解。好大一个坑,反反复复掉进去多次,最后才终于明白其中猫腻。说这个坑大,虽然讲 RESTful 的帖子不少,但是没有一个帖子说清楚,到底这个 RESTful 所代表的那个固定不变的约定到底是啥?常常刚开始觉得这个是,后来发现这个是可以改变的,后来又觉得那个是,又发现那个还是错的,当初那个头大...
其实 Rails 中有关路由的根本性约定, 在我看来只有两条,而所有其他看似约定的东西,其实根本不是约定,充其量,最多只不过是一个惯例罢了。下面就来说说这两条:
具体服务器端执行什么样的 action, 只与 URL 地址 + HTTP 动词有关。在编写 Rails 代码时,我们通常不关注真实的 URL, 仅仅关注对应的命名路由 (即:???_path, ???_url 之类的东西.)
所谓 RESTful, 其实是指针对数据库的某个操作(CRUD)
与 命名路由 + 动词
的唯一约定。这就是 RESTful 中那个唯一的约定_.
我们假设具体到一个对象 product, 则:
POST
动词调用products
命名路由.(注意,有个 s, 是复数)PUT
动词调用product
命名路由。(注意,这里和下面是单数)DELETE
动词调用product
命名路由.
针对嵌套形式的 RESTful, 只不过是在父对象之上,针对子对象添加 RESTFul 形式路由而已。一样满足上面的三条约定,请自己去体会。这就是 RESTful 所有的猫腻... 命名路由作为一个中间媒介,使应用程序产生了很大的弹性,我不妨再解释一下这个路由的流程:
具体的一个网址 + HTTP动词
, Rails Server 则查找路由表,来确定需要执行的 action. 这是自下向上的流程,这一步很好理解了。RESTful形式的命名路由 + HTTP动词
是什么,否则应该通过自己来指定命名路由 + HTTP动词
. 而这些命名路由,会根据由表,动态的转化为一个具体的 URL, 并最终通过 erb 引擎,产生最后响应给浏览器的 HTML 代码。在这里,我给大家几条建议:
在编写 Rails 代码时,你只需要专注于`命名路由 + http 动词', 以及对应的 action 是什么,你永远不应该考虑 URL 地址的形式,因为 URL 地址是 Rails 的路由表该考虑的事情
在使用 RESTful 来操作数据库时 (例如使用 form_for 表单操作数据库), 你应该总是专注于 对象当前的被操作状态', 然后根据之前的约定, 找出对应的
命名路由 + http 动词' 对应的 action
如果你希望更改默认的 RESTful 形式的路由约定 (例如对于 form_for 表单), 你可以通过指定哈希参数 `:url => ???_path' 的形式来指定一个新的 path
最后,还有一个好大的坑,等着你来跳 (至少我是跳过的)
就是具体调用 view 下的那个模板,跟真实的 URL 没有任何关系。
不知道我讲清楚没有,我觉得 Rails 初学者 (至少以我个人的经验来说), 最坑爹的就是这个 RESTful 啦!不过这也是 Rails 的魅力所在!有什么不对的地方欢迎指正!!
学过 Ruby 的人都知道,Ruby 里面,类的实例变量的用途为:_就是将一个本地变量的 生命周期
延长到整个类对象,并且方便在各个实例方法中分享数据,我刚接触 Rails 控制器的实例变量也是这样想的,后来才发现,Rails 控制器中的@实例变量
完全不是干这个的。如果你是个初学者,对于控制器中那么多 action 中定义的那么多实例变量感到困惑,我想用一个抽象点的说法来解释:
有关url_for
的简写方式 (例如:link_to, button_to, respond_to 等), 这个其实没什么好说的,用 Rails 久了,自然明白。不过初期的确给像我这样的新人很多困扰,其实就两条:
URL位置参数
(就是 product/:id 当中的:id 这个 symbol), 而 path 中只有这些位置参数 (没有传递其他额外的参数), 此时可以不写哈希键,直接写命名参数
的 value 即可。Passing a record (like an Active Record or Active Resource) instead of a Hash as the options parameter will trigger the named route for that record, The lookup will happen on the name of the class. So passing a Workshop object will attempt to use the workshop_path route. If you have a nested route, such as admin_workshop_path you’ll have to call that explicitly (it’s impossible for url_for to guess that route).
其实 Render 没啥。就是简写方式太坑爹。(如果这也算是约定优于配置
的话,在 render 上绝对发挥到极致了)
首先要讲的是:render 有两个,一个是 view 中用,另一个是在 Controller 中用。(不知道 Model 中有没有??)
这一点刚开始也让我曾经产生过困扰,事实上,对于任何 http 动词的任何请求, 你都可以以哈希的形式传递一个请求参数给控制器 (通过 params), 只不过纯 GET 请求,通常都只是纯响应一些信息,更多的情况下,是 POST 请求,例如一个按钮,用来提交请求数据到控制器中的 action.
下面是林林洒洒,从笔记中挑捡出来的一些常见的惯例,老生常谈的调调,我就不提了。大家都懂的。我只是提一下通过自己的体会,总结出来的其他一些惯例,这些惯例很多其实应该都是 web 开发的惯例,有些是 Rails 独特的惯例,了解这些惯例,会让你更好的理解 Web 开发。
凡是需要 id 的地方,你都可以直接传递对象。
经常查询的字段 (例如外键或需要 where 的字段), 你总是应该添加索引的。
发起一个请求,在 Rails 中其一定有一个路由来匹配请求。
View 中包含多个参数且存在 block 的方法,应该给普通参数添加括号。
声明 has_many 时,总是应该添加附加的约束
__大部分情况下,Rails 中的`符号和字符串'是可以相互替换的,应该优先使用符号形式。
提交模型表单时,对应的浏览器 URL 都是无意义的,甚至多数情况下,你根本不会注意到它 (因为总是 redirect_to, 除非添加了验证)
redirect_to 和在浏览器内打入一个网址,其实没啥不同
在 Rails3 中,针对 Model 的build方法'和
new 方法'其实没啥不同???__ (这个需要高手来验证我的推论!!)
两种形式的`命名路由', ???_path, ???_url, 在物理层面上,对于浏览器其实没有区别.(更多的来自于语义)
谨慎的使用<%= ... %> 以及 <% ... %>.
局部模板在布局模板之前完成 render 操作的 其实就是把真个 View 模板作为一个 block 而已,可以好好研究下 yield.
即使在 Model 内,也应该使用访问器方法来模型的字段。(如果使用实例变量,当你存在`不代表字段'的实例变量时,很容易混淆)
给 Model 编写方法时,如果可以用实例方法实现,就不应该用类方法来实现。
Rails 用不到 ruby-debug, 一个好的调试惯例是:
<% ... %> 表达式中可以是任意的 Ruby 表达式,<%= ... %>之中的=方法,行为可以近似的理解为 to_s.
你可以给模型表单传递一个:url 哈希参数,来跳过 RESTful 形式的默认路由。
任何时候,你都不应该在 view 直接创建一个对象 或 声明一段对象的关系., 你总应该通过控制器来传递对象给视图。 貌似很多代码并不遵循这个约定,例如在视图中会存在:@post.comments.each, @post.comments.new, 这应该是错误的, 你应该在控制器中声明这些逻辑,然后在 view 内使用它。如果你不遵循这个约定,例如在视图中,会经常出现一些莫名其妙的问题。
如果你需要验证一个东西是否是合法的,你首先需要验证,这个东西是否真实存在?
find_by_id(:id) 和 find(:id) 两者的表现是完全不同的。
路由嵌套
永远不应该超过两极嵌套,如果存在超过两级的关系,应该写为两个 resources block, 而且,应该总是使用 shallow 参数。
有关 Model hook 方法的一些惯例:
善用 rake db:schema:load
你必须明白的两个很浅显的道理:
你应该总是首先 skip_before_filter 公共的过滤器,然后再添加自定义的 before_filter.
有一个惯例:在控制器中的 before_filter 之中,几乎总是使用 unless 跳转... end...
使用 Ajax 刷新 partial 时,时刻记着,不要忘记从 action 传递所需变量给 partial 模板。