RoR是一个比较神奇的东西,首先建立在一个神奇的语言Ruby之上,有点颠覆我们过去对编程语言的认识(甚至包括一些面向对象的语言),Rails更发扬光大了这一点,其设计者简直是个软件架构的天才,他制定了Rails的“宪法”,使整个开发工作简洁、高效又不失灵活性。 如果把编程当成盖房子,Ruby就是盖房子的材料,过去的编程方式是盖一个砖结构的房子,使用的材料是砖块,方式是用砖块堆垒起来;而Ruby就是新型材料预制件,通过预先做好的连接组件搭起来。 Ruby的创始人是一个日本人,Yukihiro “matz” Matsumoto,他经常说的两句话表明了Ruby的特点和诉求: "Trying to make Ruby natural, not simple” --更自然而不是简单
"Ruby is simple in appearance, but is very complex inside, just like our human body".--就像我们的身体一样,看似简单,其实复杂神奇。 因此,习惯于过去开发方式的我们就可以发现下面一些神奇之处:
Rails哲学 Rails的设计目标是提供一个简洁、高效的Web应用开发框架,当然所有的框架都是这么说的,但Rails有自己的价值观和哲学,让我们回顾一下,其实非常简单,就两条: --DRY 不要重复自己,开发是最大限度的考虑代码的重用,代码的迁移,也包括重用现有和别人的代码 --COC 约定胜于配置,Rails抽象了绝大部分应用开发的过程和需求,并提供了自以为优秀的解决方案和框架,杜绝的大部分配置工作和冗余无效信息,实际上也确实做到了这一点,随着使用的深入,我们会深深的理解这一点。 例如,如何声明一个变量是本地变量、进程变量还是全局变量: var,@var,$var 就可以了! 再如,如何定义一个函数(方法)的返回值,用return吗?No. 方法中的最后一个值就是返回值!! 简单吧!现实中有一个很好的比对例子是jquery(一个javascript框架)。 以上是官方的说法,从我看来,Rails还有两个核心哲学观: 1. 简洁、简洁、到简无可简 Rails不鼓励使用冗长的代码实现复杂的特性,从用户使用的角度来说也希望应用简单、快速并容易理解和使用。这让我想起了一个对”完美“的诠释:"完美不是增无可增,而是减无可减"。
2. 更接近人的表述和思维方式 看大师们的代码就像看到一个非常有条理的人在说话,一切都是那么自然和流畅。
自带开发环境 我们过去开发,首先是考虑IDE(集成开发环境和工具),需要编译器、类库、扩展模块、Web服务、数据库服务、测试支持、调试环境、多语言、版本控制、协作开发....,搭建一个完整的开发环境需要来自不同厂商和技术的很多软件,将它们组装在一起并协调工作本来就是一个比较挑战的工作。 Rails就比较简单了,安装完成后,这些东西基本上都有,如果需要扩展,也可以在线或者自动(使用bundler技术)来进行扩展,只需要一个命令。这样,我们只需要一个比较好的编辑器、命令行程序、和浏览器,就可以进行开发了,这个也能够保证我们的开发和部署支持跨平台和异构环境。
一切都是对象 我们通常说某语言是面向对象的,比如Java,但仔细相信,好像Java也有一些基本类型,Ruby在这方面走的更远,基本上完全对象化了,由此我们可以看到更简洁神奇的代码: 5.times { print "我们爱 Ruby -- it's outrageous!" } 上面的代码打印五次“我们爱Ruby”,5这时是一个对象,调用了times方法。你甚至可以改编这个类,如添加一个Plus方法:
class Numeric def plus(x) self.+(x) end end
y = 5.plus 6 # y is now equal to 11
再如,如果要倒排一个字符串,应该怎么处理呢?: "Jimmy".reverse "Jimmy".length
数组方法: [12, 47, 35].max
简约而不简单
看看下面一行代码,叫块( do ... end),实现遍历,生成一个数组。
search_engines =%w[Google Yahoo MSN].map do |engine| "http://www." + engine.downcase + ".com" end
列出目录下的文件: Dir.entries "/" 给数字排序: [12, 47, 35].sort
文件修改时间的小时数: File.mtime("/Home/comics.txt").hour 下面定义了一个函数,参数是某个文件,函数遍历文件的所有行,将用冒号分隔的名称和地址保存在一个哈希集合中并返回:
def load_comics( path ) comics = {} File.foreach(path) do |line| name, url = line.split(': ') comics[name] = url.strip end comics end
迭代器Iterator
迭代器是对象语言的一个非常重要的概念,表示一个对象集合,也是非常重要的一个功能。如何实现处理集合中的对象(如遍历)也是程序语言的一个非常重要的特性,Ruby实现的简洁而直观,可以使用each方法: #!/usr/bin/ruby ary = [1,2,3,4,5] ary.each do |i| puts i end
更简单的是使用collect方法: #!/usr/bin/ruby a = [1,2,3,4,5] b = Array.new b = a.collect c = a.collect{|x| 10*x} puts b puts c
命令行界面
图形界面可能代表直观,但不一定(通常不)代表高效。例如: rails new demo 这个命令创建了一个名为demo的应用程序,想想我们在IDE里面怎么做的吧,新建项目-起个名字-项目模版-程序设置....-保存,大概要点十几下鼠标吧。另一个例子是为当前应用程序启动Web服务器: rails server 或者启动单元测试: rake test:unit
最简化的配置
先想想struts中的配置吧,web-config,action,class,tag lib,result,map ...。Rails中就简单太多了。 Rails自认为了解你开发的需求,并且做出了很好的安排,消除了大量冗余信息和多余环境,也降低了错误的几率,就大大简化了开发过程中的配置:
--命名方式 Rails会自动处理类名、控制器名、视图(模版)名、对应的文件名、数据库名...,甚至可以很好的处理单数和复数(如表名是类名的复数) -- 在控制器中定义重定向
即便如此,我们还是需要做一些配置工作: --数据库配置 位于 config/database.yml 文件中,在此可以一次定义开发、测试、生产三种环境中的数据库连接配置。
-- 应用根路径和路径映射 位于 config/route.rb 文件中,通常需要定义程序首页(系统默认的首页是一个静态文件 public/index.html),其他的路径映射通常会自动配置,需要时可能要做相应调整。
生成器 Rails中有一个强大工具,生成器,使用简单的命令行,就可以创建和修改M、V、或者C。 想想我们过去是怎么建立模型的吧,我们会编辑一个文件,创建类,定义属性和方法,然后为模型创建数据库表,进行配置和映射...,如果要修改呢,再来一遍... 我们看看Rails怎么处理,执行两个命令就可以了:
rails generate model Product title:string description:text image_url:string price:decimal rake db:migrate 第一个命令利用创建一个product模型,包括所有相关的类定义文件,第二个命令在此基础上真正创建数据库结构。有趣的是在模型文件中我们看不到属性的定义(应该在数据库表定义中吧),而且在数据库结构中自动创建了一些字段如自增id,创建和修改时间等等。要修改这个模型: rails generate migration add_category_to_product categroy:integer rake db:migrate Rails会明白,在product模型(数据表)中添加一个categroy字段。
如果还想更省事,可以使用脚手架scaffold,它可以一次生成MVC:
rails generate scaffold Product title:string description:text image_url:string price:decimal 这个命令可以生成一个完整的信息类应用程序架构: 项目列表-项目详情-项目添加-项目修改-项目删除,系统自动生成所有相关的视图(列表视图、详情视图、增加表单、编辑表单)和操作(增加、修改、删除)和数据库模型。
动态方法 看一个查找方法的例子,在模型中显然没有定义这样的方法,但Rails就知道可以通过增加的后缀来进行处理,很直观,很聪明了吧?! Order.find_by_name("Dave Thomas")
Order.find_all_by_name("Dave Thomas") Order.find_all_by_email("[email protected]")
模型关联 在Rails中定义对象关系很神奇也很简单,只需要在模型定义中增加声明就可以了,系统会自动处理相关的依赖性,如 --订单和发票的一对一关系: 订单模型中: has_one: invoice 发票模型中: belongs_to: order
--订单和项目的一对多关系
订单模型中: has_many: line_items:dependent => :destroy 项目模型中: belongs_to: order
--分类和产品的多对多关系
分类模型中: has_and_belongs_to_many :products 产品模型中: has_and_belongs_to_many :categroies
--利用中间模型实现的多对多关系,可以中间模型加入一些处理和逻辑
订单项目模型: belongs_to :order belongs_to :product
订单模型中: has_many: line_items:dependent => :destroy 产品模型中: has_many: line_items
视图部件
我们经常会遇到需要循环显示一个数组或者集合的情况,例如下面的视图定义显示购物车项目:
Rails使用循环标签 for item in items...end 来显示items集合中所有的元素,一行一个,看起来不错。但我们有更好的方式:
这里只需要渲染一个集合cart.line_items,当然我们需要做些其他的工作,在相应视图文件夹中创建一个_line_item.html.erb文件就可以了:
<%= line_item.quantity %> |
<%= line_item.product.title %> |
<%= number_to_currency(line_item.total_price) %> |
这里我们创建一个视图部件_line_item.html.erb,渲染时Rails知道会调用这个视图模版,并且自动循环显示。
Javascript支持 在Web应用中适当引入javascript可以大大提升应用体验,Rails也可以集成javascript技术(应该是procotype库),看看下面的例子: 增加一个按钮,用于清空购物车: <%= button_to '清空购物车', @cart, :method => :delete%>
通常我们会提示用户确认,我们通常希望调用一个js confirm函数,而利用Rails,这里需要增加一个confirm成员信息就可以了,Rails会使用JS在客户端实现: <%= button_to '清空购物车', @cart, :method => :delete,:confirm => '你确认吗?'%>
JS的另一项热门技术是AJAX,我们看看Rails怎么处理。
还是以购物车为例,设想在商品项目点击添加到购物车,项目会调用AJAX添加到购物车列表中,页面不需要刷新。要实现这个,基本上需要四个设置:
1. 在页面中的合适位置定义一个内容块,将来AJAX调用返回的内容将显示在这个块之中
<%= render @cart %>
2. 告诉按钮提交使用remote设置(添加成员:remote => true)
<%= button_to '添加到购物车', line_items_path(:product_id => product),:remote => true %>
2. 在控制器的create方法中增加提供js格式的数据输出,和remote提交对应
if @line_item.save
format.html { redirect_to(store_url) }
format.js
format.xml { render :xml => @line_item,:status => :created, :location => @line_item }
else
...
4. 定义js输出内容,
需要视图目录中创建一个create.js.rjs的文件,内容如下: page.replace_html('cart', render(@cart)) 意思是将渲染内容输出并刷新对应区块的内容。 我们看到,Rails的实现不需要改变程序框架和结构,不需要修改客户端内容,也不需要编写和调用AJAX代码,确实令人耳目一新!
I18n国际化 全球经济一体化使我们的程序有机会在全世界范围内被使用,一个良好的框架必须对此有良好的支持,而Rails的实现方式也是那么简单而优美: 1. 首先为不同的语言定义资源文件,格式为yml 2. 做好相应的设置,如声明包含这些资源文件和设置默认语言 3. 在程序中使用,最简单的方式是直接使用神奇的t 对象: <%= t('Title') %> 4. 当然还有更高级的用法,如基于域名/URL,基于视图的命名空间,系统本地化....
|