在很多时候,下拉菜单选项是专门做一张查询表,显示里面的某个字段,这张查询表可能会被经常改动。所以,动态的下拉菜单是常见的。举个例子:
在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
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
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) references pay_types(id)"
add constraint fk_order_pay_types
foreign key (pay_type_id) references 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>
...
<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
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}
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
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
Object.const_get(symbol.to_s.capitalize).find(:all, :order => 'name').collect { |item| [item.name, item.id] }.insert(0, ['Please select...', nil])
end
本文转自 fsjoy1983 51CTO博客,原文链接:http://blog.51cto.com/fsjoy/89010,如需转载请自行联系原作者