前面的代码创建了一个查看和修改数据库的功能完全的界面,不过,所有格式化、显示以及业务逻辑(比如本来就有的)都由 Rails 动态完成,没有任何重大修改。为了创建一些更为定制的内容,需要生成更多一些代码。现在我们所需要的是让 Rails 显式地写出它在运行时隐式地生成的所有支架,以使得我们能够修改它。
图 8. 显式控制器和视图代码生成
[~/Sites/AddressBook]$ ruby script/generate scaffold Contact
dependency model
[...]
create app/views/contacts
exists test/functional/
create app/controllers/contacts_controller.rb
create test/functional/contacts_controller_test.rb
create app/helpers/contacts_helper.rb
create app/views/layouts/contacts.rhtml
create public/stylesheets/scaffold.css
create app/views/contacts/list.rhtml
create app/views/contacts/show.rhtml
create app/views/contacts/new.rhtml
create app/views/contacts/edit.rhtml
|
现在有了更多一些要做的,所以尝试去修改一些内容。(注意此代码已经重新使用了复数格式 contacts,我不清楚其原因;现在我们需要接受它。)尝试在 CSS 中修改一些颜色和字体:
清单 9. 配置层叠样式表单
[~/Sites/AddressBook]$ head -8 public/stylesheets/scaffold.css
body { background-color: #ffe; color: #338; }
body, p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
}
td { border: 1px solid; }
a { color: #eef; background-color: #446; }
a:hover { color: #fff; background-color:#000; }
|
您已经拥有了这段代码,那么 contacts_controller.rb 做什么?就其操作而言,它比前面的代码中所出现的 contact_controller.rb 更为显式且可配置。控制器类似如下:
清单 10. 控制器 app/controllers/contacts_controller.rb
class ContactsController < ApplicationController
def list
@contacts = Contact.find_all
end
def show
@contact = Contact.find(@params['id'])
end
def create
@contact = Contact.new(@params['contact'])
if @contact.save
flash['notice'] = 'Contact was successfully created.'
redirect_to :action => 'list'
else
render_action 'new'
end
end
|
如前所述,控制器的主要任务是将数据导入到变量之中。对象 Contact 是模型所提供的 ActiveRecord 对象-关系映射。变量 @contacts 或者 @contact 是它们的适当方法中所给出的数据。通过 URL 可以访问那些方法本身,比如 http://rails.server/contacts/show/2 (这一个方法显示出 id 为“2”的联系人)。
此示例中的控制器最终连接到了视图,即 RHTML 文件,它们使用的是控制器导入到变量中的数据值。例如,这里是 list 视图的一部分:
清单 11. 列出视图 app/views/contacts/list.rhtml
[...]
<% for contact in @contacts %>
<tr>
<% for column in Contact.content_columns %>
<td><%=h contact.send(column.name) %></td>
<% end %>
<td><%= link_to 'Show', :action => 'show', :id => contact.id %></td>
<td><%= link_to 'Edit', :action => 'edit', :id => contact.id %></td>
<td><%= link_to 'Destroy', :action => 'destroy', :id => contact.id %></td>
</tr>
<% end %>
[...]
|
方法 ContactsController.list 导入变量 @contacts,RHTML 中的流控制标签从数组中取出单个的记录。
|
初始的模型只包含联系人的名字。不幸的是,本文中我已经没有余地扩展这个模型以使其包含实际的联系人数据,比如电话号码、地址、电子邮件等等。通常,那些数据应该存放在一张子表中,子表的外部关键字关联到表 contacts。Rails 模型会使用类似这样的定制代码来指明关联:
清单 12. 定制代码 app\models\phone.rb
class Phone < ActiveRecord::Base
belongs_to :contact
end
|
在结束之前,让我们来对数据模型稍加修改,以查看它如何影响应用程序。首先,添加一列:
清单 13. 向模型添加 first_met 数据
$ cat add-contact-date.sql
USE AddressBook;
ALTER TABLE contacts ADD first_met date;
$ cat add-contact-date.sql | mysql
|
既然已经修改了底层的模型,http://rails.server/contact/ —— 支架的后台版本 —— 就会直接调整过来,不需要您做什么。控制器和视图是完全自动基于模型的。不过,在 http://rails.server/contacts/ 上应用程序版本使用了我们手工编写的文件,并不是那样自动化的。
list 视图将 Contact.content_columns 作为模板循环的一部分,能够自动查找 所有 的列,不管它们是什么。不过,edit 等其他视图已经被生成了,需要添加新的数据域。例如:
清单 14. 编辑视图 app/views/contacts/edit.rhtml
<h1>Editing contact</h1>
<%= error_messages_for 'contact' %>
<%= start_form_tag :action => 'update' %>
<%= hidden_field 'contact', 'id' %>
<p><label for="contact_name">Name</label><br/>
<%= text_field 'contact', 'name' %></p>
<p><label for="first_met">Known Since</label><br/>
<%= date_select "contact", "first_met", :use_month_numbers => false %></p>
<input type="submit" value="Update" />
<%= end_form_tag %>
<%= link_to 'Show', :action => 'show', :id => @contact.id %> |
<%= link_to 'Back', :action => 'list' %>
|
那么您手工修改的应用程序看起来如何了呢?与默认的区别不太大,不过在图 3 和 4 中可以看到修改已经生效了:
图 3. 列出联系人,修改后
Rails 为您提供了开发灵活的 Web 应用程序的一种极其快速的途径;本篇介绍只是肤浅地涉及了如何使用 Rails。完整的框架包含很多实用的类和方法,能够完成基于 Web 的应用程序使用最多的操作。
Rails 的最大价值在于它孕育了一个成体系的“Rails 思维方式”,因为您所需要的所有支持代码令它变得完整。相对于只是给出要使用的原始材料的其他工具包和框架而言,这是一个巨大的优势。Rails 开发为您提供了将半成形(half-formed)的想法实现为功能完全的 Web 应用程序的一条坦途。