第一个RoR程序depot建立过程

1、首先利用rails depot建立rails应用,进入depot目录
//2、在depot目录下建立数据库 mysqladmin -u root create depot_development
配置应用时,可直接利用命令ranlis --database mysql depot,同时生成与depot应用相关的数据库depot_development

2、测试配置是否无误:
rake db:migrate
检查是否能连到数据库,在MySQL下,用mysql -u root depot_development
检查是否能建表:mysql> create table dummy(i int); mysql> drop table dummy;
3、创建products model 和maintenance application
通过ruby script/generate scaffold ModelName ControlerName
现在,我们建立了一个depot应用,并且建立了一个数据库连接到depot project.我们创建了一个product controller和product model,使用migration传教相应的products表
4、运行ruby script/server
改进2
1、表中增加一列:depot> ruby script/generate migration add_price_to_product price:decimal
2、修改add_price_product方法
3、rake db:migrate实现修改model即数据库中表后的应用
4、注意我们上面只关注了model层,control层未作改动,现在我们还需要做的就是修改view层。
文件depot_a/app/views/products/index.html.erb为显示层代码,需加入列price的显示

改进3 验证
1、validate的使用,注意,我在先前加入列image_url时,错写成了imag_url

改进4 优化页面显示
1、增加测试数据,先迁移:ruby script/generate migration add_test_data1
然后修改add_test_data方法
2、找到相应美化的图片和css放到public的stylesheet目录下
3、修改*add_test_data1文件
4、rake db:migrate完成更新

Task B Catalog Display
B1 创建目录列表:
1、ruby script/generate controller store index , 用来建立一个新的控制器,控制器中的方法index,似乎一个控制器对应一个页面,用控制器的名称作为路径可以访问,因为在view中自动生成了控制器store的一个目录
2、修改控制器类的index方法,使它能调用Model Product类的方法找到所有产品
3、在model中的Product类中写找所有产品的方法
4、修改view中的store页面
B2 增加页面layout
1、在view/layout下增加与控制器为名字的文件store.html.erb,这样,相应的控制器会默认地使用这个Layout
关于其中的一些语法标签,如stylesheet_link_tag将会使用public/stylesheet里面对应文件名的.css文件来显示
访问store页面过程:从layout中与控制器同名的store.html.erb来显示,这个文件中的yield :layout会自动替换view中产生的store内容到此处,
这种方式也可以用@content_for_layout来做,不过使用yield显得更sexy
B3 使用helper方法来格式化price
直接修改view中的代码则不是很好的选择,用helper方法的number_to_currency转换值为货币方式显示
B4 链接到cart
增加一个链接到按钮Add to Cart 到页面,使用标签Button_to标签,而不是link_to标签,因为后者发送get请求,不会做任何行动,而前者则发送post请求,并可以传递参数,由服务器相应
在修改view/store/index.html.erb后,由于按钮是一个块元素,它将显示在下一行中,我们要使它显示在Price之后,就要修改对depot.css,加入按钮显示的方式inline内嵌

Chapter 8 构建 购物车
8.1 sessions:它是类似于Hash的集合,rails用它来存储请求过程中的键值对
在数据库中放置sessions:
1、先用rake db:sessions:create创建sessions数据库的迁移,然后运行迁移:rake db:migrate
2、把config/environment.rb的"#config.action_controller.session_store = :active_record_store"的#号去掉
这样,depot应用将把session数据存到数据库中,目的是:把session数据保持到应用之外存储,以便在需要时被多个应用程序共享
sessions and Browsers
默认情况下rails实现用cookie来存储session id 在用户浏览器上。
为了防止同一个服务器上运行不同的应用,就需要用不同的cookie名来存储它们的session keys,否则可能会造成混乱
在rails命令建立应用时,它为cookie确定了一个名称,用来存储session id,这个名称包含了该应用的名称,它是通过
app/controllers/application.rb文件来完成这个过程的。我们需要插入一行来确定session id 的值,并且去掉下一行中secret的注释
现在,我们需要建立一个对购物车对象的查找,并且能把它保存在用户session中,所以建立了方法find_cart,它被建为私有,使得在类外部不可见

Task C1 建立购物车
1、建立cart.rb在app/models下,作为一个activeRecord
2、views/store/index.html.erb下加入按钮相应的action方法add_to_cart和参数id
3、控制器目录下controllers/store_controller.rb加入add_to_cart方法
4、此时需要把执行add_to_cart方法后的情况显示出来,rails会自动找views/store/add_to_cart.html.erb文件,于是我们需要建立该文件

Task C2 建立更好的购物车
1、在models下建立cart_item.rb,它作为存储购物车中的项成立,它拥有俩个属性:product和quantity
2、这样cart.rb中添加产品的方法就要改变了,先前是加入product,现在是加入CartItem,但是传入的参数均是product,只是要更新quantity的值
3、改变views/store/add_to_cart.html.erb文件的部分显示内容
问题:当我们把页面刷新时,session中存储的已经加入购物车的产品信息均会丢失,我们可以把session信息加入到数据库session表中,刷新时只要根据id查找相应的session,返回给用户即可

Task C3 处理错误
1、在我们刷新页面时,会出现类似http://localhost:3000/store/add_to_cart/4的url,4表示id,如果用户把4随便改成一个其他不存在的id,就会出现报错页面,我们修改这个错误显示,使用户不致以为是工程编写错误
2、rails定义了一个flash结构来处理错误和错误报告,它类似于一个hash表,flash的内容在这个session自动被删前的下次请求时是有用的,它特别是用来记录错误信息,在views下,利用flash的accessor方法是可以存取flash信息的
3、我们把add_to_cart方法重写,加入异常处理,(因为显示的页面就是由于该方法产生)把错误分别重定向到log文件和flash[:notice]中。
4、修改对store控制器的通用模板layouts/store.html.erb,把错误显示的方式(调用id = "notice"的css styling 显示)加在该文件中,然后加入一个显示的style,这里在public/stylesheet/depot.css中写一个id 为notice的css styling。

Task C4 完成购物车
1、增加清空购物车的按钮,首先在depot_h/app/views/store/add_to_cart.html.erb增加该按钮和相应的方法
2、在depot_h/app/controllers/store_controller.rb增加empty_cart方法
3、另一种empty_cart方法:把提示和转向放在redirect_to_index中,这样不用到flash
4、对add_to_cart方法进行升级,加入到购物车的产品能分别显示它们的价格和所有产品价格之和,这要把models中的cart类加入计算价格之和的方法
5、显示在depot_i/app/views/store/add_to_cart.html.erb里改

Task D1 移动购物车
1、partial template把它当成对views的一个方法,简称为partial,你可以通过模板或者控制器来调用一个partial
2、这里我们使用partials两次,先看看它在购物车中显示它自己
开始:1、我们的目的是把add_to_cart.html.erb(之前为)的页面显示在store。html.erb的左边sidebar上
2、修改layout/store.html.erb,在里面加入partial template,该view模板的名称为_cart.html.erb,即显示_cart.html.erb中的内容在侧边栏
3、_cart.html.erb的显示内容和add_to_cart.html.erb相同,但是其中的@cart被替换为了cart,因为@cart在store.html.erb中作为对象参数传递进来了,这里用cart与@cart传递的对象名刚好相同,即是cart类型的
4、为了保证页面其他部分显示不变,则把页面重定向到index,给用户的感觉是只加入了sidebar的内容,这样定义重定向到index以后,控制器不再转到默认的add_to_cart.html.erb,所以该页面也就没有用处了

Task D2 基于ajax的购物车
1、首先在app/views/store/index.html.erb(显示在store.html.erb的主要部分,由yield完成)下修改,加入form_remote_tag helper方法,用submit_tag来代替button_to来添加按钮“Add to Cart”
2、在app/views/layouts/store.html.erb里加入<%= javascript_include_tag :defaults %>,保证用户的浏览器能使用javascript库
3、在用户点击“add to cart”后,由store控制器的add_to_cart方法处理,前面的方法是重定向到主页,现在调用respond_to来用一个.js格式的javascript来响应,这样add_to_cart完成对ajax请求的处理
4、虽然我们完成了添加这个过程,但没有对用户显示出来,respond_to给出相应的js文件,我们通过编写add_to_cart.js.rjs这个js模板文件在views/store下,它告诉我们替换<div>的id为"cart"的内容为"cart" partial模板的内容,这个partial模板为_cart.html.erb

Task D3 高亮度改变
出现问题:没有得到预期效果
1、我们前面说过,javascriopt_include_tag helper会把许多javaScript库下到浏览器里,在javascript库中,有一个effect.js能帮助你装饰许多显示效果,其中的一个是Yellow Fade技术,它高亮显示一个元素,我们要利用它来响应当前操作在购物车里面的变化
2、我们有一个方法来标记最近改变的item,这个工作从Cart 层开始,我们让add_product返回CartItem对象
3、在store_controller.rb中调用了add_product方法,把其返回值赋给current_item,该值作为一个全局值,在 _cart_item.html.erb中增加的那一行item进行highlight

Task D4 隐藏Empty Cart:在购物车为空时,我们让它不显示出来
1、最简单的方法是<% unless cart.items.empty? %>加在_cart中硬编码;
2、1的方法虽然可以,但是它要重写侧边栏,我们用更smooth的方式来处理,使用Script.aculo.us effects库中的blind_down,它能平滑地显示购物车,直至消失
3、当我们点击EmptyCart按钮时,希望购物车不要再显示出来(因为购物车为空)。为了抽象出对view的处理,我们写一个helper模块的方法hidden_div_if,使购物车不显示出来
4、修改EmptyCart方法,由于执行controllers方法后需要重定向到一个页面,我们把它指向index

Task D5 当浏览器用户禁止使用javascript时
1、在我们使用ajax的标签 form_remote_tag以前,使用刷新的方式显示内容,如果javascript被禁,就可以用原来的方式显示页面内容
2、当我们点击form_remote_tag里的按钮时,有两种情况发生:如果javascript被禁将使用HTTP POST请求引发目标动作,它如同普通的form来工作;如果javascript可用,它将覆盖传统的POST方法,使用JavaScript对象确立与服务器的连接,这个对象是XmlHTTPRquest类的实例,简写为xhr
3、服务器接到请求在做出页面view响应前,我们只需判断请求的类型是否为xhr,如果是则可以用ajax,否则重定向到index页面

Task E Check out付账
Task E1 获取预订
1、在数据库中建立order表和line_item购物项表,ruby script/generate model order,然后在db/migrate里面写入创建表的方法
2、rake db:migrate更新数据库
3、Models之间的关系,在Order Record类和Product Record类中加入has_many,说明(1对多的关系?),在LineItem类里加入belongs_to,说明belongs_to后的类不为空,否则该类不存在。
4、创建Order获取的Form:首先加入Checkout按钮在depot_p/app/views/store/_cart.html.erb;如果购物车非空,则生成一个订单类,否则现在购物车为空;执行完该方法后,将转到对应的checkout.html.erb文件,建立这个文件。在该文件中form_for 是一个form helper方法,<% form_for :order, :url => { :action => :save_order } do |form| %>第一个参数表示处理实例变量@oreder,url表示点击按钮后,将产生http post请求,由控制器中的save_order动作来处理
5、唯一tricky的事情是下拉列表,我们定义选项数组PAYMENT_TYPES在Order.rb中,以防忘记,二维数组的第一个元素作为下拉列表的项显示,第二个值存储在数据库中。如果我们把这个二维数组存于另一个表中,在rails下也是很方便的,只要传递给select helper 在表中find的结果就可以。
6、实现save_order动作
7、最后一点ajax的改进:在提交订单后会提示“Thank you for your order”,如果此时继续添加,这个提示不会消失,我们通过page.select("div#notice").each { |div| div.hide }来消除这个提示,它表示隐藏所有显示过#notice的div

Task F 管理
Task F1 添加用户
1、首先,使用脚手架生成一user表,相应地会产生控制器、Helper、view、与model,里面包含姓名、hashed_password,salt三个元素,salt用来与hashed_password一起生成sha1编码后的密码,它们会产生160位的hash
2、rake db:migrate
3、修改对User类里元素的验证,如非空、密码验证等过程,注意attr_accessor 类型的password_confirmation对应第二次输入的密码,它只作为一个暂存变量,不会保存在数据库中,所以在User类里面定义它
4、写产生Hash密码的方法encrpted_password和产生salt的方法,这些方法都是对外不可见的,我们在用password方法来生成hashed_password时、用authorize来验证用户身份正确性时,就要用到这两个私有方法
5、管理用户:在已经生成的用户控制器中,已有show、create、edit、destroy等方法,修改相应的代码,使得创建用户和更新用户信息后返回users的Index页面
6、最好,我们要更新用来建立新用户的form,在new.html.erb页面提交form,似乎是由create方法处理,并把它存入数据库中,但是为什么是create来处理呢?
7、然后在users的Layout代码users.html.erb中加入depot。css
Task F2 登录界面
1、我们需要一个form来填写用户名及密码;一旦登录,我们要记录其sessin,直到退出登录;控制应用的权限,仅仅允许登录用户来管理store
2、建立控制器,与三个动作login logout和index,使用命令ruby script/generate controller admin login logout index
3、修改login动作和index对应的方法和显示页面
Task F3 限制存取权限
1、我们在所有控制器的父类中加入autherize方法做权限验证,保证为登录用户不能进入系统
2、但是这个权限管得太大,store控制器也被包括进去了,我们可以在store控制器中覆盖authorize方法,来避免store也需要用户验证才能进入
3、我们保证用户在登录以后能转到它登录以前的那个页面,需要保持登录以前的uri,这就要修改authorize和Login方法来达到目的
Task F4: 侧边栏,更多的管理
1、我们在ApplicationController这个父类中加入layout "store",则可以把它所有子类的控制器对应的页面都显示store的layout;注意,为什么我们这里的users控制器没有显示这些页面呢?这是由于脚手架生成了users.html.erb在layouts中,我们删除它后即可显示出侧边栏了。
2、为防止删掉所有用户,导致不能管理,在destroy方法里加入异常
3、最好做了两件事:1、把丑陋的代码@cart=find_cart写成一个方法(我没有做这步)2、在使用find_cart前要保证为清空购物车,即:empty_cart不异常
Task G
有时候市场部人员要给已订购过书的用户发送邮件,可以通过如下方法来找到想要联系的用户,REST类型接口表示用http verbs在应用间发送请求和响应
这里的例子是找出某中产品的订单
1、建立product类和订单的一对多关系,在Product类里加入申明
2、建立控制器info与相应的动作who_bought,who_bought用来找查产品订单,authorize覆盖使得我们不用登录系统
3、写显示订单的xml文件who_bought.xml.builder与html文件who_bought.html.erb,对不同的请求用不同的文件来响应
4、产生整个工程的文档:rake doc:app,用rake stats来查看

在此,我们建立了inPlaceEditing工程,作为rails for recipes的内容

Rails in Depth
14.2 目录结构
app/和test/:大部分工作都在这两个目录中,
doc/目录存放应用程序文档,如果用doc:app命令,会生成HTML文档在doc/app目录下
lib/目录存放不能简介地放在model,view,controller下的代码,例如你写的一个用户可下载PDF收据的库,这个库直接从控制器发送到浏览器(使用send_data方法)
Tasks,这是lib/下的一个空目录,可以在此写rake tasks,例如这里我们写db_schema_migrations.rake来查看迁移的日志
script/包含一些脚本程序,如server,generate等


14.2、(中文版) ActiveRecord
model类与同名的复数数据库表相连,我们可以用ActiveRecord基类的columns()方法来得到它的属性信息

CRUD的介绍
condition、limit参数、offset参数

下部分讲控制器

Chapter 15 Active Support
Active Support是所有rails组件共享的库
15.1、一般的可用扩展,rails把ruby对象扩展了两个方法to_json和to_yaml,他们可以把对象转成JavaScript Object Notation 和YAML (the same notation used in Rails configuration and fixture files)
rails还扩展了一个blank?方法,用来判断对象是否为空,空格,fals,nil均为真
15.2、枚举和数值
groupby方法:groups = posts.group_by {|post| post.author},把author作为Key,author对应一组具有相同author值的集合
Rails扩展的另外两个方法:index_by方法是把一个集合转换成一个hash,其中的元素的key由传递进去的参数给出 state_lookup = us_states.index_by {|state| state.short_name}
sum方法是把所有的元素值传递给块,然后返回块中所有元素为一个集合total_orders = Order.find(:all).sum {|order| order.value }

15.3、字符串扩展
string = "Now is the time"
puts string.at(2) #=> "w"
puts string.from(8) #=> "he time"
puts string.to(8) #=> "Now is th"
puts string.first #=> "N"
puts string.first(3) #=> "Now"
puts string.last #=> "e"
puts string.last(4) #=> "time"
puts string.starts_with?("No") #=> true
puts string.ends_with?("ME") #=> false
count = Hash.new(0)
string.each_char {|ch| count[ch] += 1}
puts count.inspect #=> {" "=>3, "w"=>1, "m"=>1, "N"=>1, "o"=>1,
"e"=>2, "h"=>1, "s"=>1, "t"=>2, "i"=>2}

puts "cat".pluralize #=> cats
puts "cats".pluralize #=> cats
puts "erratum".pluralize #=> errata
puts "cats".singularize #=> cat
puts "errata".singularize #=> erratum
puts "first_name".humanize #=> "First name"
puts "now is the time".titleize #=> "Now Is The Time"

当单复数转换出现问题时,可以自定义于environment.rb文件的最后

15.4、对数的扩展
puts 3.ordinalize #=> "3rd"
puts 321.ordinalize #=> "321st"
puts 20.bytes #=> 20
puts 20.kilobytes #=> 20480
puts 20.megabytes #=> 20971520
puts 20.gigabytes #=> 21474836480
puts 20.terabytes #=> 21990232555520
puts 20.petabytes #=> 22517998136852480

puts 20.seconds #=> 20
puts 20.minutes #=> 1200
puts 20.hours #=> 72000

puts Time.now #=> Thu May 18 23:29:14 CDT 2006
puts 20.minutes.ago #=> Thu May 18 23:09:14 CDT 2006
15.5、时间和日期的扩展
now = Time.now
puts now #=> Thu May 18 23:36:10 CDT 2006
puts now.to_date #=> 2006-05-18
puts now.to_s #=> Thu May 18 23:36:10 CDT 2006
puts now.to_s(:short) #=> 18 May 23:36
15.6、Ruby Symbol扩展

15.7、with_options
把众多重复选项放在with_options中
15.8、Unicode 支持
Unicode有三种编码形式UTF32 UTF16 UTF8,Rails中把字符串存在Unicode中,使用utf8
Ruby库对Unicode支持不好,但是在Rails中写了一个Chars类来解决这个问题,这个类建立了和类名相同的方法,调用后会将字符串转化为Unicode编码>> name.length 与>> name.chars.length
要想保持字符编码的正确,还要保证从浏览器到数据库各个数据路径都使用相同编码,举一个Unicode Name的应用例子
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值