四、开发时间Web应用
好了,正式开始我们的DEMO吧,先建立一个数据库。Rails对很多数据库提供了支持,对MySQL支持最好,真是开源爱开源啊。我们就用MySQL建立一个数据库,这个数据库只有一个表,用来保存留言的。这个表需要那些东西呢?先创建四个字段吧,每条留言标识,留言标题,留言内容,留言时间(我是故意设这么少的属性,让你看看Rails应付需求变更的强大)。打开MySQL的GUI工具,建立数据库,数据表,四个字段。
注意:Rails有个原则,约定优于配置。也就是你按照一定的约定(规定)编码,你就能享受更多的优待,不需要J2EE,.net那些烦人的配置文件。哪些约定呢?我记得的也比较乱,就随便侃侃吧。
Rails认为所有的变量名都应该小写,如果变量名由多个单词组成那么两个单词之间应该使用下划线相连,类名则应该使用混合大小写,每个单词的首字母使用大写,单词之间没有下划线,类名对应的文件名则小写,两个单词之间使用下划线相连。然后就是类名与数据库之间对应了,Rails认为数据库表名都使用和变量名一样的命名习惯,全部使用小写,单词之间用下划线相连,而且表名始终应该是复数形式。
比如在这里留言本里我们的留言表是posts,这就表示这个表里有很多post(很多留言)。数据表名全部为小写,如果是两个单词的,两个单词之间用下划线相连。对于posts这个表它对应了模型的post.rb这个文件,在app/models目录下,类名是Post,还会对应一个PostController的控制器,文件名为post_controller.rb,位于app/controllers目录下,对应一些视图文件在app/views目录下的post目录。如果你按照这个规则,Rails是会自动的将它们关联起来的。每个数据表还必须有一个名为id的列,这是一个标识列,整型,自增。对于时间字段一般以_at结尾。
还有ruby的一些命名习惯,比如方法的命名,如果这个方法是作判断的,返回布尔类型的值,那么在这个方法名后加一个“?”,如果这个方法执行了危险性操作,比如要摧毁数据,那么就在这个方法名称后加一个“!”。
我们来实战吧。首先,创建建表, 如图14所示:

图15 建立留言表posts
数据库建立好后我们来配置数据库连接参数吧,在Apatana左边的Rails Navigator里打开config文件夹,选择database.yml文件进行编辑。下面的代码清单就是一个示例文件,为了节约版面我删除了注释。关于yml的更多细节可以google或者百度一下。
注意:关于这个配置文件有几点要注意的地方。上面三个带有“:”的标签表示针对不同运行环境,还记得图13么,服务器可以在三种环境下运行,开发,测试,产品。adapter就是使用那种数据库了,这里使用mysql数据库。database表示数据库名称,username数据库用户名,这里看到了使用了root权限,如果到了产品环境这是不安全的。password数据库密码,host:数据库服务器名或者IP。
为了方便我这里将三个环境的数据库都配置为一样的(真实环境中这也是建议的)。还有一个要注意的地方非常奇怪,这个属性和的“:”和后面的值之间有一个空格,如果这个空格被删除了则会发生错误,不能正确的读取。比如这个password,“:”和后面的851025(打个小广告,851025鄙人生日)之间有一个空格,这个空格是必须存在的,删除了就识别不出来密码了。
代码清单1: database.yml文件
development:
adapter: mysql
database: book
username: root
password: 851025
host: localhost
test:
adapter: mysql
database: book
username: root
password: 851025
host: localhost
production:
adapter: mysql
database: book
username: root
password: 851025
host: localhost
数据库建立好了,数据库连接参数也配置好了,该是我们的脚手架工具上场了,打开Apatana,然后展开底部的Generators窗口,在下拉列表里选择scaffold,下面选择Create,右边输入Post,它会自动对应到数据库的posts,其他默认设置,然后GO。就这小小一个的一个操作,产生了多少代码,又是多少功能,作为一个.net程序员我为之感到惊叹。
至于生成的代码我们就不细谈了。让我们启动服务器来测试一把吧。一切都有了,功能都齐全了,只是界面不太好看。留个言试试,如图15所示:

图16 脚手架工具自动生成的留言界面
瞧瞧留言列表 如图16所示:

图17 留言列表,也是自动生成的
客户看到这两个页面后很兴奋,不过兴奋之余又有了新的需求:你的这个留言内容怎么还用个文本框作为输入呢,应该是文本域嘛,还有,留言应该还有昵称的嘛,如果你是在用.NET作开发你倒霉了,改啊,改啊,调试啊,调试啊。然而这时使用的却是Rails,一切都那么简单。打开数据库,改一下数据表,添加一个字段 nickname,将content的类型转为text。如图18所示:

图18 修改后的数据库表
然后再次启动脚手架工具,不过这次Options中的Force选择上。简单,太简单了,看看新的留言窗口,content变成了文本域,也添加上了nickname。如果细心的读者会发现实际上这次修改,模型,控制器的代码都没有改变,改变的只有视图文件,这就是ORM的力量,所以我们可以只修改数据库,然后修改视图文件达到同样的目的。
以为这样就可以下班了,可客户跑过来大叫道,你的这个留言本也太。。。。(这里省略若干字),怎么留言时间还要留言者输入啊,端杯茶给客户,让他消消气。这不简单,看我的,挽起袖子,继续Rails之旅了。
首先我们要删除留言视图文件里面的输入时间部分,找到这个输入表单并不简单,找到视图文件下的post目录,打开new.rhtml,edit.rhtml,我那熟悉的时间输入呢,怎么没有呢?来研究一下new.rhtml,如下代码清单2所示,
代码清单2 new.rhtml
<h1>New post</h1>
![]()
<% form_tag :action => 'create' do %>
<%= render :partial => 'form' %>
<%= submit_tag "Create" %>
<% end %>
<%= link_to 'Back', :action => 'list' %>
看这一句<%= render :partial => 'form' %> DHH告诉我们,这叫做局部模板。这里的“form”是局部模板的名字,它的意思就是把_form.rhtml(下划线开头,然后跟上局部模板的名字)这样一个文件里面的内容插入到这里来。好,我们打开_form.rhtml文件,如下清单3所示:
<%= error_messages_for 'post' %>
![]()
<!--[form:post]-->
<p><label for="post_title">Title</label><br/>
<%= text_field 'post', 'title' %></p>
![]()
<p><label for="post_content">Content</label><br/>
<%= text_area 'post', 'content' %></p>
![]()
<p><label for="post_create_at">Create at</label><br/>
<%= datetime_select 'post', 'create_at' %></p>
![]()
<p><label for="post_nickname">Nickname</label><br/>
<%= text_field 'post', 'nickname' %></p>
<!--[eoform:post]-->
终于看到了时间输入的地方,删除它:
<p><label for="post_create_at">Create at</label><br/>
<%= datetime_select 'post', 'create_at' %></p>
好了,现在总没有这个该死的时间了吧,叫来老板测试,看到界面后老板很高兴,当客户输入数据测试后发现留言列表里面这个留言没有时间,火了,你当我不懂吧,你就欺骗我。在赔礼又道歉之后你打开post_controller.rb这个控制器文件,找到create这个方法,在save方法调用之前添加了一个 @post.create_at = Time.now,ok,这下完美解决了,如下清单所示:
代码清单4 修改后的post_controller.rb的create方法
def create
@post = Post.new(params[:post])
@post.create_at = Time.now
if @post.save
flash[:notice] = 'Post was successfully created.'
redirect_to :action => 'list'
else
render :action => 'new'
end
end
好了,今天终于可以手工了。
五、总结
本来只想作一个Aptana这个工具的一个介绍,最后写着无意间插入了很多Rails的知识内容,夜已经晚了,管理员老头又要来敲门了,所以后半截写的有点匆忙,有时间完善一下吧。孤独的一个人写着论文心里真的不是个滋味,真的希望能看看心中的那个她。远方的你,知道我的心么?