[RoR]Agile Web Development with Rails 3rd depot疑难杂症

[RoR]Agile Web Development with Rails 3rd depot疑难杂症

depot项目任务E check out一章很长,最后playtime中有两个题。
(1)在checkout.html.erb页面不应该还有 [checkout] 按钮
(2)把payment_type字段分离成一个表。

第一个相对简单一点,最省事儿的办法是,设置一个标志字段,然后在layout/store.html.erb中判断一下。
第二个就比较复杂,
(1) generate migration, 重建数据表,修改数据表
(2) generate model PaymentType ,修改Order,添加一对一的映射关系。
(3) 修改store_controller,在checkout中加入@payment_types的取得方法,将对应的view中select部分的静态数组改成这个@payment_types。
(4)因为这个payment_type比较特殊,在order里头并不保存type的id,而是保存name(就是缩写),所以编码的时候需要注意字段的对应关系。不过注意一下的话,问题不大。

结果,第二个跑出来有问题,在checkout页面输入订单信息并选择支付方式,全通过,则没问题,数据库里也都正确。但是一旦有任何输入为空或不合预期,则报错:

 

You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.map

 

傻了……
因为对payment_type的获取方法也不是很肯定,所以一开始怀疑问题出在表结构映射关系上,反复检验后没发现问题。
然后怀疑页面传参问题,参数传不到这种rp问题……加之之前有几处rails版本区别,觉得对rails的一些约定还是不太了解。
然后试着修改页面,将checkout view的select那一段

collection_select :pay_type,:name,@pay_types,:name,:display_name,
  options
= {:prompt => " Select a payment type " }


改成

if  @pay_types then
  collection_select :pay_type,:name,@pay_types,:name,:display_name,
  options
= {:prompt => " Select a payment type " }
else
  form.select :pay_type,PaymentTypes::STATIC_TPYES,
   :prompt
=> " Select a payment type "
end


 

页面倒是不会出错了,不过心里总留了一个疙瘩,而且事实上每次出错后都会从PaymentTypes::STATIC_TPYES中取支付类型,也不符合playtime的初衷。这说明某些情况下@pay_types的确是nil了,但是反过来,为啥呢?
忽然一下想起,要是@pay_types为空的话,第一个去按钮的任务也应该不成功,检查了一下,的确如此。

但checkout页面确确实实的显示出来了,说明checkout view被调用了,然而参数是空的。这是我想到看看checkout之后有些什么操作——
checkout提交到save_order,成功则重定向到Index,而失败则render到checkout页面。


注意到这里的render。render和redirect_to都会根据checkout.html.erb的内容进行布局,而二者的区别在于,redirect_to会重定向到action对应的函数中重新执行,而render则不会。具体在这里区别就是render不会执行checkout里关于获取
@pay_type的那一段逻辑,从而导致@pay_type为空,自然呈现出来的html中@pay_type就会出错。

在save_order里面加上生成@pay_types的初始化方法,刷新之后问题解决。
问题应该是找到了,但不知道是不是最好的解决办法。因为save_order和checkout中存在代码重复,可以考虑重构一下。


 

 

你可能感兴趣的:([RoR]Agile Web Development with Rails 3rd depot疑难杂症)