rails2.x中的scaffold脚手架生成的页面中,delete那里已经不再是用botton_to方法了,生成的不再是一个form表单,而是一个普通的a标签。但rails的作者DHH非常反对对delete操作使用get的方法提交参数,他还是推荐用表单提交的方式处理delete,所以他做了件很bt的事,给delete的那个a标签监听click事件,然后用js生成一个表单提交。也就是说,他还是通过表单提交的delete,只是不通过html显式地这么做,而是通过javascript。。。
看看这个变态的a标签吧:
================================
<a onclick="if (confirm(‘Are you sure?’)) { var f = document.createElement(‘form’); f.style.display = ‘none’; this.parentNode.appendChild(f); f.method = ‘POST’; f.action = this.href;var m = document.createElement(‘input’); m.setAttribute(‘type’, ‘hidden’); m.setAttribute(‘name’, ‘_method’); m.setAttribute(‘value’, ‘delete’); f.appendChild(m);var s = document.createElement(‘input’); s.setAttribute(‘type’, ‘hidden’); s.setAttribute(‘name’, ‘authenticity_token’); s.setAttribute(‘value’, ‘6o2LD8EdrS7QGLPLdtvQNhC9hjw5ODIjM1ajNr9yx2Q=’); f.appendChild(s);f.submit(); };return false;" href="/publishers/2">Destroy</a>
================================
在rails1.x里,脚手架的格式是ruby script/genrate scaffold modelName controllerName action1 action2
控制器的名字是由我们指定的,另外还可以指定action名。到了rails2.x,脚手架的格式是ruby script/generate scaffold modeName a:string, b:string
控制器名称不能指定,会自动生成和模型名相对的controller名。需要注意的是rails2.x 后面接的a:string, b:string,这里a和b是对应的数据库中表的字段名,在1.x里,自动生成的view会将数据库中的字段自动放到view里,形成表单项,而2.x中view生成哪些表单项是需要我们给脚手架传参时指定,如果不指定的话,那么生成的view里将一个表单项也没有。

1) 用stylesheet_link_tag方法和javascript_include_tag方法生成的<link>和<script>链接会在地址后面自动加上最后修改日期,例如/stylesheets/style.css?1150321221,以去除缓存的影响,让修改马上生效。
2) rails内置了很多验证,在提交表单时,可以直接使用rails提供的验证。rails中关于程度和数据库的连接环节是在model里的,在model里使用validates_xxxx_of可以完成常用的验证。常用的有:
<1> validates_presence_of 用于验证非空(输入空格也算空);
<2> validates_numericality_of 用于验证数字
<3> validates_uniqueness_of 用于验证唯一
<4> validates_length_of 用于验证字节长度
<5> validates_format_of 用于验证指定格式
另外还可以定义 validate方法,它会在模型类在保存实例之前会自动调用这个方法。
需要说明的是,这些验证都是服务器端验证,不是前端通过js的验证。如果验证不通过,会自动生成一串错误提示信息,包含在form最前端。
如:
=============================================
class Product < ActiveRecord::Base
validates_presence_of :title, :description, :image_url
validates_numericality_of :price
validates_uniqueness_of :title
validates_format_of :image_url,
:with => %r{^http:.+\.(gif|jpg|png)$}i,
:message => "must be a URL for a GIF,JPG, or PNG image"
protected
def validate
errors.add(:price, "should be positive") unless price.nil? || price >= 0.01
end
end
=============================================
3) 局部模板。 布局和视图都可以直接使用控制器中的变量,但局部模板不行。局部模板传参有两种方式,一种是通过:object => xxxx传参,用于单数情况,一种是:collection => xxxx传参,用于复数情况。这两者传参给局部变量时,局部变量内部通过和模板名同名的变量可以得到传进来的参数,例如:
=======================
new.rhtml:
<%= render(:partial=>’article’,
bject=>@an_article) %>
_article.rhtml:
<p>this article’s name is <%= article.name %></p>
=======================
如果传给:partial参数的是一个简单的名字,那么rails会在当前控制器对应的view目录下去查找模板。如果我们需要一个被多个action共享的模板,可以给:partial传带"/"的参数,这样rails就会从app/views根目录开始查找对应的模板。rails习惯把共享局部模板放在app/views/shared目录下,使用的时候如:
=============================
<%= render(:partial => ’shared/post’, :collection => @article_list) %>
=============================

今天在做demo的时候,需要用到表单,照书上的例子写了
<%= form_tag :action=>’save’, :id=>@user %>
<%= end_form_tag %>
结果刷新页面报错。
查了下,原来在rails2.x中,end_form_tag已经去掉了。
改用下面的方式就可以了:
<%= form_tag :action=>’save’, :id=>@user %>
</form>
ps 查到一个不错的blog,推荐一下(虽然他说的<% end -%>我试过不管用):http://blog.csdn.net/kunshan_shenbin/archive/2009/05/17/4195113.aspx

rails里集成了rake工具,它是个类似于java下的ant的工具,可以用它来批量完成一些“任务”。其中之一就是可以用来做数据库的迁移工作。在rails里,数据库的操作可以不通过直接操作数据库完成,而是使用rails的迁移功能,它使用一种特殊的语言:DSL,使用DSL可以做到数据库中心,它并不直接使用sql语言,而是使用自己的DSL语言描述需要的数据库操作,然后不同数据库在rails中安装不同的驱动程序,将不同数据库的操作,通过驱动程序去转化DSL语言,从而做到数据库中心。
DSL语言是放在迁移文件中的,在用generate model或者generate migration的时候,会自动生成迁移文件,它在db/migrate目录下。每个迁移都必须实现self.up和self.down这两个方法(方法名会自动生成)。
DSL常用的语句有create_table(table_name,options)、column(column_name,type,options)、add_column(table_name,column_name,type,options),drop_table(table_name)等。如:
========================================
class CreateAuthors < ActiveRecord::Migration
def self.up
create_table :authors do |t|
t.column :first_name, :string
t.column :last_name, :string
t.timestamps
end
end
def self.down
drop_table :authors
end
end
========================================
运行迁移动作,是通过rake db:migrate实现的。但它默认情况下是针对开发环境的,如果要改变环境,需要用到RAILS_ENV,如:
========================
RAILS_ENV=production rake db:migrate
========================
用rake生成的数据库,会生产指定的新数据表,同时还会生成一个schema_info数据表,这个表只有一个字段,用以记录当前数据库架构的迁移版本号。指定的新数据表中,除了我们指定的字段,还会自动生成id字段,如果不希望自动创建id字段,可以给create_table加上:id => false选项。另外还会自动生成created_at和updated_at字段。

今天在做demo的时候,发现rails报路由错误,查找再三,最后发现原来还是版本的问题。现在的参考书大多是1.2版本的rails,而系统已经升级到2.x版本了,按照参考书去做例子,是会遇到意料外的问题的。
引起路由问题的原因是config/routes.rb文件,它是用来设置路由解析模式的文件,在1.2版本中,它的默认值是
map.connect ‘:controller/service.wsdl’, :action => ‘wsdl’
map.connect ‘:controller/:action/:id’
而到了2.x,它的默认值是
map.connect ‘:controller/:action/:id’
map.connect ‘:controller/:action/:id.:format’
我们只要将它修改成1.2中的形式,就可以正常显示页面了。
放个地址大家看看:
http://www.workingwithrails.com/forums/4-ask-a-rails-expert/topics/58-no-route-matches-with-method-get-error-in-awdwr-book
鬼佬们也在头疼版本的问题。。。

1)ruby可以将对象序列化,以字节流的等式保存,也许是内存,也许是数据库,然后在需要的时候再将它反序列化,还原成对象。rails就可以利用这一点,在session中保存对象,但需要注意的是,如果依赖rails来动态加载类,在尝试重新构造session数据的时候,rails可能还没有加载其中某个类的定义。因此,应该在控制器中用model声明来列举所有需要序列化的模型类。
2) 在渲染视图的时候,是通过在action中调用render方法实现的,如果不指定render方法,那么rails会依照惯例,调用和action命名相关联的视图。但其它在渲染视图的时候,视图是由两部分组成,一部分在app/views目录下,是这个action直接相关的视图,另一部分在app/views/layouts目录下,它是最终视图的布局页面。比如说几个页面有相同的页眉页脚,侧边栏,只是主体内容部分不同,我们可以在layouts目录下定义一个布局,在views目录下定义主体部分的内容,最终的视图就会让两者结合起来。
声明布局有两个地方可以:
1)控制器的最前面,用layout声明,它会让整个控制器中所有action都使用指定布局,layout支持:only和:except修饰符来指定哪些action使用布局。
2)在action内部,给render方法传参:layout可以指定该action的layout。
============================================
class StoreController < ApplicationController
layout "standard", :except => [:rss, :atom] #layout nil 可以禁用布局
def rss
render(:layout => false) #不使用布局
end
def checkout
render(:layout => "layouts/simple")
end
def test
end
end
============================================
另外,layout除了可以接收字符串,也可以接收符号,使用符号的话,可以动态修改layout指向,如:
============================================
class TestController < ApplicationController
layout :determine
def determine
if params[:id].nil?
return "fancy_layout"
else
return "default"
end
end
end
============================================
如果不指定layout的话,rails默认会在layout目录下查找到控制器同名的rhtml或rxml文件作为布局,如果没有则会使用application.rhtml这个页面作为布局文件,它是针对所有action的全局性的布局。
3)在布局中可以和视图中一样,使用控制器中的实例变量,除此之外,布局中还可以通过controller得到控制器的实例,例如<%= controller.action_name %>可以得到当前控制器当前的action名。布局引用视图,可以通过@content_for_layout变量,也可以通过yield关键字,如:
========================
<%= yield %>
<%= @content_for_layout %>
========================
4) ruby语言处理异常真方便,可以先执行一条语句,如果语句有错误,直接在后面加个语句异常就行,挺方便的。
===========================
self.authors.map do |a|
a.name
end.join(", ") rescue ""
===========================

看书真的是件很有收获的事,特别是看好书。在看一些有思想的作者的书的时候,你能得到的不仅仅是一些语法api之类的,你能理解到事情的前因后果。除此之外,还会有很多作者自身的一些观点,针对我们实际工作中经常会遇到的问题,大师们的观点是盏明灯,吸收这些观点,往往是比语法更大的收获。也许你见不到大牛,也许你一辈子没法跟他们面对面交谈,也许你的周围全是些不喜欢技术或者在你看来技术过于落后的人,没关系,读书吧,挑本好书,读书的过程本身就是同他们交谈。
想从今天起,以后多收录一些大师们的语录。
“ 要是看到你在模板中写这种代码,很多人会怒不可遏。别理他们——他们都是教条主义的受害者。在模板里写代码没有任何不对,只要别写太多(尤其是别把业务逻辑放进模板)。”
—— David Heinemeier Hansson 评论mvc模式中,v中带有少量逻辑判断
摘自《应用rails进行敏捷Web开发》中文版 第343页
【感想】:看到这句话的时候,我相当有感触,不仅仅是对mvc模式,而是更进一步的“教条主义”。我发觉“教条主义”是件非常普遍的事,哪个领域都存在这种现象,很多很多的工程师死守着教条在做事,好的坏的用一刀切的形式去判断,往往这种人不在少数,还非常地固执。这似乎是个顽疾,起初在遇到这种工程师我还试图想去跟他们解释,但发现这种解释要花相当大的精力才有可能成功。
教条主义其实是观点片面造成的结果,一方面可能是实战经验不够,另一方面可能是对“教条”的起因不明,或者干脆是人云亦云缺乏自己思考造成的结果。比如说在早期的重构中,很多人就坚持不用table,非要使用div来模拟table,这就是非常典型的教条主义。虽然table的问题现在已经广泛解决了,绝大多数工程师都有了可以合理使用table的意识了,但教条主义仍然没有就此结束。很典型的就是“页面是否一定要通过w3c验证”,我一直觉得w3c的验证不过是促进web标准化推进的手段,它本身不是目的。web标准的目的是1)让标签语义化; 2)结构、样式和行为分离。这是表象,更进一步,为什么要让标签语义化啊?因为标签语义化有助于seo,有助于特殊终端在无css支持的情况下仍然让网页有很好的可读性。为什么要让结构、样式和行为分离啊?因为分享结构样式和行为有助于提高代码的可维护性。制定web标准的验证,不过是对我们的重构代码进行一次评估,提供一个标准的模板供你去匹配,它是种一刀切式的判断。一定要完全通过w3c验证才算是好的页面吗?这个叫本末倒置。我们的目的是seo、去样式可读还有代码的高可维护性。只要实现这个目标,是否通过验证其实并不重要。死守“通过w3c验证”其实就非常的“教条主义”了。
另外,还有mvc,css sprite,oo编程等等等等,很多方面都需要根据具体情况来决定怎么做,比如说我个人就觉得小型网站使用css sprite非常不值得,可维护性下降了许多,开发成本提高了很多,换来的好处却非常有限,你本身流量就不大,减少http请求数有什么价值?不是说流行的就一定是好东西,一定要知道这东西为什么流行,它能解决什么问题,然后权衡一下得失再做决定是否使用。
“要是看到你在模板中写这种代码,很多人会怒不可遏”,这的确是教条主义者们的典型写照,教条主义者们通过靠“坚持死守某个教条”来证明自己“很专业”,这其实是非常苍白的自我保护,很没劲,自己开发会很辛苦,和你一起配合的其它工程师也会非常辛苦。
“别理他们——他们都是教条主义的受害者”。是的,别理他们,他们是受害者,我们没必要跟他们大费周章地解释为什么我要这么做,为什么我没有完全遵照教条,只要认为你自己的处理非常合理,你完全可以不受他们的思想所左右,死守教条的他们才是受害者,他们会为死守教条而付出“额外的开发成本”,“可维护性下降”或者别的代价。这些代价是真的,教条救不了他们。当然,如果你非常不幸地和教条主义者共事,那么你不得不向它们解释你的视角,我知道这个过程是非常艰险的,但没办法,和人打交道的确比和代码打交道困难得多。

在webrebuild北京站上做的一次分享,总结了一下javascript的分层概念。
这里特别推荐一下YUI3给我们带来的分层概念:
1)底层(框架提供):封装DOM和Event相关操作,提供跨浏览器兼容的接口,扩展原生javascript语言本身不提供的但又特实用的接口,例如namespace;
2)抽象类层(框架提供):提供类的抽象层,用于统一框架组件层,自定义组件层和应用层中所有类的格式,例如统一初始化方法,毁灭方法,属性如何定义,监听事件在什么方法里等等等等;
3)通用组件层(框架提供):依赖底层的接口,继承自抽象类的抽象类,提供通用型组件,和项目具体需求没有直接关系,也就是说,不是定制型的组件。
4)自定义组件层(开发工程师提供):根据项目需求,定制型的组件,它依赖底层和通用组件层,继承自抽象类层,是根据具体项目进行的封装,定制型组件。
5)应用层(开发工程师提供):这一层是和页面具体需求相关的,面向应用的。用mvc来划分的话,前面四层全是m,这一层是c。它调用前面四层提供的m,集中精力在应用逻辑上。这一层如果需要自定义类,也需要继承自抽象类层。
ppt见:http://www.adanghome.com/share/javascripthierarchical.ppt

1)rails自动生成的目录中,lib目录和vendor目录分别用于存放你自己编写的组件或者第三方提供的组件,它们需要被你的应用程序用到,但又不专属于你的项目。log目录下存放的是日志文件,日志文件会针对开发环境,测试环境和生产环境分别记录。config目录是用来设置rails的配置的,其中包括用于配置服务器链接的yml文件和运行时环境配置文件等。运行时环境配置可以针对三个环境分别进行设置,公共的部分在config根目录下的environment.rb文件中设置,而针对某个环境的设置,则在config/environments/目录下的development.rb、production.rb、test.rb中进行个性设置。
2)在启动web服务器时,可以通过加上-e选项,指定启动时选用哪个环境
==================================
ruby script/server -e development | test | production
==================================
3)rails里强调“惯例重用配置”,从数据库中的表,到控制器,到模型,再到视图,命名是有关联的!文件的存放路径也是有关联的。我们在命名和存放文件时需要遵守这种惯例。一旦我们遵守了这种惯例这四者之间的映射都是rails自动替我们去完成的,这也是rails为何能“敏捷”的重要原因。
4)在编写普通ruby代码时,如果我们想要使用另一个文件中的类和模块,需要先require它们,但在rails中编程,因为rails有命名约定,所以可以不用require它们就直接使用,rails会根据命名约定(也包括路径约定),去自动加载该文件!不过,也有例外的时候,如果被引用的类要在session中保存,自动加载就会失效,但即便如此,我们也仍然不需要require,我们只需要在类里加上一句 model :类文件名(注,小字加下划线分隔)。
==================================
class StroeController < ApplicationController
model :line_item #rails会去加载line_item.rb文件,其中包含LineItem类。
==================================
5)控制器的路径默认是存放在app/controllers根目录下的,但如果我们需要在根目录下再组织一下控制器的路径,那么可以将控制器的声明位于ruby模块之下。例如,我们要将book_controller.rb文件放置于admin目录下,也就是app/controllers/admin/book_controller.rb,那么,我们就应该这样声明:
==================================
class Admin::BookController < ApplicationController
..
end
==================================
幸运的是,rails的生成器很智能,你可以直接使用
==================================
ruby script/generate controller Admin::Book action1 action2
==================================
来生成你需要的路径。
6) rails用ActiveRecord来处理对象-关系映射(ORM)。数据库中的一张表对应着模型中的一个类,表名是小写的,多单词用下划线分隔,而且是复数形式。对应的类名是单词首字母大写来进行分隔的,而且是单数形式。表中的字段直接映射成类的属性,除此之外,我们还可以给类再另外添加一些属性。表名和类名是通过命名惯例去自动对应的,(rails对ruby的字符串类进行了扩展,让它直接支持单复数之间的转变,例如 puts “cat”.pluralize #=>cats puts “cats”.singularize #=>cat),仅管pluralize和singularize方法已经很智能了,能处理child和children这样的单复数转换,但它仍然还是有缺陷,例如sheep会对应到sheeps。我们可以在模型类中,cefpset_table_name去显示地指明对应的表,而不使用缺省的惯例。
==================================
class Sheep < ActiveRecord::Base
set_table_name “sheep”
end
==================================
7)ActiveRecord从表中取出值,变成类的对象时,会自动将数据库中的类型转换成ruby支持类型,例如数据库字段是timestamp类型的,就会返回Time对象。如果你希望得到一个属性的原始值,可以在属性名称后面加上_before_type_cast。
==================================
account.balance_before_type_cast
==================================
如果在模型内部,可以使用私有方法read_attribute()和write_attribute()。
8)布尔型的数据在转换的时候会有些麻烦,有些数据库是不支持布尔型的,所以我们在工作中,可以使用0,1这样的数字来代表布尔值的真假,而ruby中只有false和nil为假,0其实是为真的。所以在数据库映射到类时,我们要判断某个属性的真假时,记得要加一个?号,这个是rails为解决布尔型问题而设置的。
==================================
# 错误写法
if user.superuser
doSomeThing
end
# 正确写法
if user.superuser?
doSomeThing
end
==================================
9) 在编程时,可以某个属性对应的是一个对象,而不是一个简单类型的数据。在类和表的映射的时候,这种复杂类型的属性也是可以直接保存到表中的一个字段的,这个字段必须是text类型的,属性会以字符串的形式存进数据据。而从数据库中映射到类时,需要在类中加以声明,某个字段是个对象,不是普通字符串。声明的方法是serialize()。复杂类型包括对象,数组,hash等等。
==================================
class Purchase < ActiveRecord::Base
serialize :last_five
…
end
==================================
10)主键。一般来说,rails都会用id作为每张表的主键,但表并不是由我们自己来建的,可能表会用别的字段作为主键。我们可以用set_primary_key来显示地指定主键字段。
==================================
class BadBook < ActiveRecord::Base
set_primary_key “isbn”
end
==================================
但需要注意的是,既然指定主键为其它字段,但在访问时,仍然可以通过名为id的属性来设置主键值,也就是说,只要使用ActiveRecord,主键字段在对象中的属性名称就永远都是id。
