在这里,我们用最基本的方式告诉大家如何使用Rails开发,通过这些内容,足够开发一个普通的网站,因为使用最基本的方式,所以难免达到最佳实现,甚至会比较丑陋,但是,这无疑是最低成本的学习。阅读本文需要一定的基础,比如如何使用generate script 身成model,controller等
1.必须明白的几件事情
1)任何一个action对应一个同名字的template,这个action中的instance variables在template中可见(其他地方均不可见)
2)我们认为任何controllers,views目录下的class和template可见models目录下的class,或者说,action pack component可以使用active records component 提供的class(我们这里先不谈layout)
2.从 Active Records Component 说起,解决对单张表的维护
操控数据要依靠active records component,我们关心的是model目录,ActiveRecord::Base class提供了对数据库存取的支持(注意是存取支持),我们说过model的作用是用来存取数据和约束数据,因此程序员要做的就是在model目录下面的class中填充约束数据的代码以及有关的存取操作(建立在存取支持的基础上)
简单的例子:
我们建立了一个关于友情链接的表
create table links(
注意表中必须有一个名字为 id 的主键,并且设置为auto_increment |
如何操作其数据?
1)建立有关的model
>ruby script/generate model link
2)建立有关的controller
>ruby script/generate controller main
3)从数据库中读取数据
ActiveRecord::Base class提供了对数据库存取的支持,model下面的类都是继承于ActiveRecord::Base的,所以我们建立的link class就有了一些可用的method,最重要的就是find
前面说过,我们认为models目录下的class在controllers下是可见的,也就是这样做是合法的
class MainController < ApplicationController
def index
@links = Link.find_all # 使用ActiveRecord::Base中的find_all方法
end
end
find method 介绍:
find method可以说是最重要的方法之一了
可以通过3种从数据库取回数据的方式使用find:
a.通过每个表中的 id 的值进行检索(因为每个表都有id列),例如:
find(1) # 读取 id=1 的行
find(1,4,9) # 读取 id=1,4,9 的行
这种方式,如果只有一个id,返回这个行对应的object,如果有多个ids,返回一个数组包含这些object
b.使用first,取回第一条数据
find(:first) # 读取第一条数据
这种方式,返回一个对应行的object
c.使用all,取回所有数据
find(:all) # 取回所有数据,相当于find_all
这种方式,返回一个数组,如果没有找到返回一个空数组[]
使用option hash,最后一个参数可以使用一个option hash,options有:
:conditions 表示sql语句中where子句后面的条件部分
:order 表示sql语句中order by子句后面的部分
:limit 表示取回行的数量
:offset 设定偏移量
:select 设定sql语句中select a,b,c form ... 中的abc部分
options不仅仅是这几个,还有几个比较大家可以参考Rails API,下面细细说明:
find(:all,:conditions=>"id < 5") #注意第一个argument不能少,而option hash只是可选的
find(:all,:limit => 5,:conditions =>"id <100") #limit限制,读取仅仅只有5行
find(:all,:select => "id,link") #指定表中列名
find(:all,:select => "link",:order => "id desc") #使用id降序排列
以上的options可以任意组合,不分顺序
4)显示数据库中的数据到template
前面定义了一个action index,何如在index.rhtml中显示出来?如下:
(请确保表links中有数据)
<% @links.each do |row| %>
<% end %>
前面讨论过h method,这里就不说了。之所以上面的代码可以运行,是因为action中的instance variables共享给了对应的template。
运行结果:
5)保存数据到数据库
一个重要的method:save,save是ActiveRecord::Base 中的一个method,因此在所有子类中,我们都可以获得save这个method
一类重要的method:每个表对应一个class,这个class将含有存取数据库中列的method,method名字与列名相同
下面是一个简单的例子:
class Link < ActiveRecord::Base
def Link.add_link(web,link)
rows = Link.new # 产生一个对象new不带arguments
rows.web = web # 与表中的列同名
rows.link = link # 与表中的列同名
rows.save # save用于保存数据
end
end
class MainController < ApplicationController
def index
@links = Link.find_all
Link.add_link("Google","http://www.google.com")
end
end
运行http://localhost:3000/main 后,数据库会增加一笔数据:
a.理解 ActiveRecord::Base
model中继承来自 ActiveRecord::Base 的类,可以实现对列的存取操作,如何理解?通过new方法,生成的object包含2个实例变量:@new_record 和 @attributes ,@new_record用来判断是新插入的行,还是进行update,@attributes用来保存列值。
print Link.new.inspect
结果:
#<link:0x39949c4 @new_record="true," @attributes="{"link"=">"", "web"=>""}>
class Link < ActiveRecord::Base
def Link.add_link(web,link)
rows = Link.new
rows.web = web
rows.link = link
rows
end
end
print Link.add_link("Google","http://www.google.com").inspect
结果:
#<link:0x385d100 @new_record="true," @attributes="{"link<font" color="#000000">"=>"http://www.google.com", "web"=>"Google"}
由此我们知道,前面的rows.web,rows.link,web 和 link 只是 Virtual Attributes。所有的列值到@attributes,以待save或者读取。
b.关于new
new可以不带arguments,这时候@attributes中所有列对应一个空字符串
new也可以带一个argument,这个argument要求是一个hash object,key是列名(即可以是String literal 也可以是 symbol literal)(补充:注意这里也可以使用params[:key] 来实现 update_attributes(params[:key])的功能)
new创建的对象 @new_record = true
c.关于save
save会根据@new_record来进行判断,是建立一行,还是update,假如存在@new_record就建立一个新行,假如不存在就进行update操作。注意save不带parameter
d.关于update
本来是可以通过save来进行update操作的,不过它有时候不是最好的选择,比如我们现在可以得到一个hash表,进行update就很简单了,可以通过 update_attributes(hash object) 完成,这个method是很有用的,我们会结合表单提交部分做些实例
3.表单提交
表单有最重要的3部分
1)开始:<%= start_form_tag(:action => "action_name") %>
2)提交按钮:<%= submit_tag("submit") %>
3)结束:<%= end_form_tag %>
注意template中使用的是helper methods
上图完整的显示了如何进行一个重要的操作---update。这里面涉及到了参数的传递问题,这里要强调的隐含含义:
params是Hash的子类(HashWithIndifferentAccess)我们知道这一点就足够了,因为我们有一个重要的问题将设计到它。
params的argument---symbol object有特殊的含义,params保存input标签中处理过的name-value,具体是这样的:
对于形如:的input标签,params将有一个对应的key--- :test,这个key对应的value是一个hash object,也就是{:a=>"it is a", :b=>"it is b"},也就是保存了一个name-value对
总结来说就是:params可以保存一个name-vlaue对,这个name-value对来源与特定的标签格式,这样的格式要求name=xxx[aaa],params把xxx作为一个key(类型是symbol object),值是所有符合格式的name-value对组合而成的hash object
之后我们可以使用前面说过的 update_attributes method进行update操作,虽然我们完全可以不使用这样的方式,而使用极其原始的方式即并不约束input name,这样我们就必须在action中对表中的每一个列,写上一句代码,比如 Link.link = params[:input_name]
实例:做一个对Links表进行update的
class MainController < ApplicationController
def edit
#这里提一下,URL映射是这样的 http://app_name/controller_name/action_name/id ,所以这里要获取一个id
#所以我们传递参数的时候,没有类似 ?id=1 这样的参数
@link = Link.find(params[:id])
end
def update
link = Link.find(params[:id])
link.update_attributes(params[:link])
redirect_to :action => "edit", :id =>params[:id]
end
end
下面是template:
<html>
<head></head>
<body>
<%=start_form_tag :action=>"update"%>
Web名称
%=@link.web%>"/><p< font="">>
Web地址
%=@link.link%>"/><p< font="">>
%=@link.id%>"/>
<%=end_form_tag%>
</body>
</html>
我们注意一下%=@link.id%>"/>这行,目的是为了传递本次修改的行的id到 update action 中,Rails提供更好的办法做这个事情:
<%=start_form_tag :action=>"update", :id=>@link.id%> 也可以写成这样:<%=start_form_tag :action=>"update", :id=>@link%>
其实更多的helper methods帮我们完成了input标签,submit标签等,但是我个人觉得,这样做把程序员和设计师的工作混合在一起了,有时候并不是一个很好的选择
还要说明一下的是 redirect_to method,它是ActionController::Base中的方法,是一个十分有用的方法:
redirect_to method
redirect_to(options={},*parameters_for_method_reference)
options:
1)hash,例如:
redirect_to(:controller => 'posts', :action => 'show', :id => 10)
浏览器就跳转到 http://app_name/posts/show/10
2)链接,例如:
redirect_to("http://www.i170.com/user/killercat") #外部链接
redirect_to("/images/rails.png") #内部链接
redirect_to("/controller_name/action_name/id_name") #实现上面url_for的功能
3):back 返回前一个页面