阿当的博客











{十二月 31, 2009}   rails学习笔记(6)

   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里将一个表单项也没有。



{十二月 30, 2009}   rails学习笔记(5)

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’, :o 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) %>

=============================



{十二月 30, 2009}   end_form_tag 已经在rails2.x中去掉了

今天在做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



{十二月 29, 2009}   rails学习笔记(4)

       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字段。



{十二月 28, 2009}   rails中的路由错误问题

    今天在做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

鬼佬们也在头疼版本的问题。。。



{十二月 28, 2009}   rails学习笔记(3)

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 ""

===========================



{十二月 22, 2009}   IT大师语录系列(1)—— 说说“教条主义”

         看书真的是件很有收获的事,特别是看好书。在看一些有思想的作者的书的时候,你能得到的不仅仅是一些语法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请求数有什么价值?不是说流行的就一定是好东西,一定要知道这东西为什么流行,它能解决什么问题,然后权衡一下得失再做决定是否使用。

      “要是看到你在模板中写这种代码,很多人会怒不可遏”,这的确是教条主义者们的典型写照,教条主义者们通过靠“坚持死守某个教条”来证明自己“很专业”,这其实是非常苍白的自我保护,很没劲,自己开发会很辛苦,和你一起配合的其它工程师也会非常辛苦。

        “别理他们——他们都是教条主义的受害者”。是的,别理他们,他们是受害者,我们没必要跟他们大费周章地解释为什么我要这么做,为什么我没有完全遵照教条,只要认为你自己的处理非常合理,你完全可以不受他们的思想所左右,死守教条的他们才是受害者,他们会为死守教条而付出“额外的开发成本”,“可维护性下降”或者别的代价。这些代价是真的,教条救不了他们。当然,如果你非常不幸地和教条主义者共事,那么你不得不向它们解释你的视角,我知道这个过程是非常艰险的,但没办法,和人打交道的确比和代码打交道困难得多。



{十二月 14, 2009}   javascript的分层概念

在webrebuild北京站上做的一次分享,总结了一下javascript的分层概念。

   这里特别推荐一下YUI3给我们带来的分层概念:

1)底层(框架提供):封装DOM和Event相关操作,提供跨浏览器兼容的接口,扩展原生javascript语言本身不提供的但又特实用的接口,例如namespace;

2)抽象类层(框架提供):提供类的抽象层,用于统一框架组件层,自定义组件层和应用层中所有类的格式,例如统一初始化方法,毁灭方法,属性如何定义,监听事件在什么方法里等等等等;

3)通用组件层(框架提供):依赖底层的接口,继承自抽象类的抽象类,提供通用型组件,和项目具体需求没有直接关系,也就是说,不是定制型的组件。

4)自定义组件层(开发工程师提供):根据项目需求,定制型的组件,它依赖底层和通用组件层,继承自抽象类层,是根据具体项目进行的封装,定制型组件。

5)应用层(开发工程师提供):这一层是和页面具体需求相关的,面向应用的。用mvc来划分的话,前面四层全是m,这一层是c。它调用前面四层提供的m,集中精力在应用逻辑上。这一层如果需要自定义类,也需要继承自抽象类层。

ppt见:http://www.adanghome.com/share/javascripthierarchical.ppt



{十二月 14, 2009}   rails学习笔记(2)

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。



{十二月 02, 2009}   rails学习笔记(1)

1) 在windows系统上安装rails很简单,首先需要安装ruby,完整安装,然后先在命令行输入gem –version,如果显示出版本号,就可以直接使用RubyGems来安装rails。直接在命令行输入 gem install rails –include-dependencies就可以自动完成安装了。需要注意的是,在windows系统上配置ror环境,还会出现一些奇怪的问题,具体安装过程推荐一篇博客:http://hi.baidu.com/haoweiren1234/blog/item/1d84b53875b8ea2cb9998f79.html,博主讲解得非常清楚。

2) ruby和其它服务器端语言一样,可以运行动态脚本,格式是<% %>。如果想输出显示,可以使用<%= %>。ruby的服务器使用的是WEBrick,不是appache,不是IIS,不是tomcat哦。

3)用rails新建一个项目很简单,在命令行输入 rails xxx,xxx就是项目的根目录文件夹名。然后rails会为你自动创建好目录结构,并提供好部分代码。rails提倡的敏捷开发,很大意义上依靠于这种带有“强制性”的自动操作。rails会为你建好目录,搭好框架,我们需要做的,只是填充框架里的内容。不用置疑rails自动搭建的框架是否优秀,是否弹性十足,是否可维护性良好。rails的敏捷开发目标,目的就是为了搭一个最优势的框架。

4)新建项目之后,在命令行输入 ruby script/server,运行rails自动为我们生成的代码中的server脚本,就可以启动WEBrick服务器了。




about

打造高品质的前端代码

pages
categories
archive
et cetera