rails中使用form.select创建动态的下拉菜单

在很多时候,下拉菜单选项是专门做一张查询表,显示里面的某个字段,这张查询表可能会被经常改动。所以,动态的下拉菜单是常见的。举个例子:
 
在depot的实例中,收集订单信息时,有一项是选择付款方式,原例中是做成了一个死的数组形式,针对这个例子,下面进行改进,将这个死的下拉菜单变成动态形式。
 
首先对于form.select方法来说,接受参数第一个是对象的字段,第二个是一个数组,数组的形式是[[display1, value1],[display2, value2],[display3, value3]]  display对应于下拉菜单的选项显示内容, value是要存入对象字段的值。
 
理解了这点之后,我们着手改进。
思路是新建一个pay_types的表,里面存储付款类型和id号,在orders中修改pay_type字段为pay_type_id字段,作为外键与pay_types表进行约束。
 
那么现在pay_types表中的两个字段用来构造上面那个数组[[display1, value1],[display2, value2],[display3, value3]] ,其中付款类型为display, id为value。在最终提交表单的时候将value存到orders表的pay_type_id字段。
 
实现过程以及代码如下:
首先是数据迁移的代码:
1
class CreateOrders < ActiveRecord::Migration  
  def self.up  
    create_table :orders do |t|  
      t.column :name, :string  
      t.column :address, :text  
      t.column :email, :string  
      t.column :pay_type_id, :integer, :null=>false 
        
    end  
  end  
    
  
    
  def self.down  
    drop_table :orders  
  end  
end  
2
 
class CreatePayTypes < ActiveRecord::Migration  
  def self.up  
    create_table :pay_types do |t|  
      t.column :tp, :string, :null=>false #付款类型 
    end  
  end  
#SQL语句,建立约束
  execute "alter table orders
            add constraint fk_order_pay_types
            foreign key (pay_type_id) reference s  pay_types(id)"

  def self.down  
    drop_table :pay_types  
  end  
end  
 
 
在Order模型类中加  belongs_to :pay_type
在PayType模型类中加has_one :order
收集订单信息
...  

  <fieldset>  
    <legend>  
      Please Enter Your Details  
    </legend>  
    <%form_for :order, :url=>{:action=>:save_order} do |form|%>  
      <p>  
        <label for="order_name">Name:</label>  
        <%=form.text_field :name, :size=>40%>  
      </p>  
      
     ...  
      
      <p>  
        <label for="order_pay_type">Pay with:</label>  
         <%=form.select :pay_type_id, @types, :prompt=>"select a payment method"%> 
      </p>  

  <%=submit_tag "Place Order"%>  
        <%end%>  
  </fieldset>  

...



 
这个@types在checkout这个action中这样定义:
      @types=PayType.find_types
在PayType类中定义find_types:
#类方法,生成数组
def self.find_types  
   PayType.find(:all, :order => 'tp').collect { |type| [type.tp, type.id] } 
end  
在Order类中加入验证:
validates_presence_of :name, :address, :email  
  validates_format_of :email, :with=>/^[a-zA-Z0-9_/.]+@[a-zA-Z0-9-]+[/.a-zA-Z]+$/  
  validates_inclusion_of :pay_type_id,:in => PayType.find_types.map{|disp,value| value}
------------
但是,当所有数据全部填写正确,下拉菜单中选择了付款方式后,一切都没问题,但是如果有一项没有填写正确,包括下来菜单,也就是说无论当order对象的哪个字段成为null值,就会报错。错误信息如下:
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.inject
 
Extracted source (around line   #25):
22:     
23:       <p>
24:         <label for="order_pay_type">Pay with:</label>
25:         <%=form.select :pay_type_id, @types, :prompt=>"select a payment method"%>
26:       </p>
27: 
28:   <%=submit_tag "Place Order", :class=>"submit" %>
 
 
期待解决。。。
 
 
在AllenYoung 的文章中介绍了一个方法,当model变得多且复杂,要用到的下拉菜单多的情况下可以在applicationhelper.rb中定义下面的方法:
def get_select_options_for(symbol)    
  Object.const_get(symbol.to_s.capitalize).find(:all, :order => 'name').collect { |item| [item.name, item.id] }.insert(0, ['Please select...', nil])    
end  
通过类名来调用方法,得到数组。

本文出自 “李骥平” 博客,请务必保留此出处http://fsjoy.blog.51cto.com/318484/89010

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值