`
clark1231
  • 浏览: 247476 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

Ruby on Rails的神奇

    博客分类:
  • ruby
阅读更多

 

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("john@gmail.com")


 

 

 

 

模型关联

在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

 

 

 


 

 

 

视图部件

 

我们经常会遇到需要循环显示一个数组或者集合的情况,例如下面的视图定义显示购物车项目:

 

<table>

<% for item in @cart.line_items %>

<tr>

<td><%= item.quantity %>&times;</td> <td><%= item.product.title %></td> <td class="item_price"><%= number_to_currency(item.total_price) %></td>

</tr>

<% end %>

<tr class="total_line"> <td colspan="2">Total</td> <td class="total_cell"><%= number_to_currency(@cart.total_price) %></td>

</tr>

</table>

Rails使用循环标签 for item in items...end 来显示items集合中所有的元素,一行一个,看起来不错。但我们有更好的方式:

 

<table>

<%= render(@cart.line_items) %>

<tr class="total_line"> <td colspan="2">Total</td> <td class="total_cell"><%= number_to_currency(@cart.total_price) %></td>

</tr>

</table>

这里只需要渲染一个集合cart.line_items,当然我们需要做些其他的工作,在相应视图文件夹中创建一个_line_item.html.erb文件就可以了:

 

<tr>

<td><%= line_item.quantity %></td>

<td><%= line_item.product.title %></td>

<td class="item_price"><%= number_to_currency(line_item.total_price) %></td>

</tr>

这里我们创建一个视图部件_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调用返回的内容将显示在这个块之中
<div id="cart">
<%= render @cart %>
</div>
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,基于视图的命名空间,系统本地化....

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics