I’m not asking for help this time! In almost every Rails
project I create, I find that I want a select() popup menu that is
pre-populated by data from the database. Also, I want an “Other…”
option that presents a text_field_tag to input another (not
presented) option (basically a combo-box). In an attempt to be as
DRY as possible, I’ve come up with the following code for achieving
that. It works for me, but I wanted to see if any of y’all have any
commentary on how this could be better done (and also I wish I could
have found this when I was looking myself as an example of how this
could be done, so here it is for others).
- Peter
P.S. My model is Asset and controller is Assets (obviously), change
those instances below for your own model/controller names.
==== app/helpers/application_helper.rb ====
def select_from_db(object, method, choices, options = {},
html_options = {})
results = Asset.find(:all) if choices.blank?
if results
choices = Array.new
results.each do |result|
unless result.send(method).blank?
choices << result.send(method)
end
end
choices = choices.sort.uniq
end
choices.insert(0,"") if options[:include_blank]
choices << ["Other...","other"] if options[:include_other]
if options[:selected]
selected = "#{options[:selected]}"
else
selected = ""
end
uniqid = "#{html_options[:uniqid]}" if html_options[:uniqid]
tag = "#{object}_#{method}_#{uniqid}"
output = Array.new
output << tag('div',
options =
{ :open => true },
html_options =
{ :id => "#{tag}_div" })
output << select_tag("#{tag}",
options_for_select( choices, selected ))
output << observe_field("#{tag}",
:condition => "escape(value) != ''",
:url =>
{
:field => :select,
:action => :updateform,
:object => "#{object}",
:method => "#{method}",
:uniqid => "#{uniqid}"
},
:with => "'value='+escape(value)")
output << content_tag('span', '',
html_options =
{ :id => "#{tag}_status" })
output << "</div>"
output << tag('div',
html_options =
{ :style => 'display: none;', :id => "#{tag}_other_div" })
output << text_field_tag("#{tag}_other", '')
output << observe_field("#{tag}_other",
:condition => "escape(value) != ''",
:url =>
{
:field => :other,
:action => :updateform,
:object => "#{object}",
:method => "#{method}",
:uniqid => "#{uniqid}"
},
:with => "'value='+escape(value)")
output << content_tag('span', '',
html_options = { :id => "#{tag}_other_status" })
output << "</div>"
end
==== app/controllers/assets_controller.rb ====
def updateform
case params[:field]
when “select”
case params[:value]
when “other”
render :partial => “show_other”, :locals => { :params =>
@params }
else
render :partial => “hide_other”, :locals => { :params =>
@params }
end
when "other"
render :partial => "hide_other", :locals => { :params =>
@params }
end
end
==== app/views/assets/_show_other.rjs ====
tag = “#{params[:object]}#{params[:method]}#{params[:uniqid]}”
page << “if (Element.visible(’#{tag}_other_div’) == false)
Effect.SlideDown(’#{tag}_other_div’);”
page << “$(’#{tag}_other’).focus();”
page << “$(‘submit’).disabled = true;”
==== app/views/assets/_hide_other.rjs ====
tag = “#{params[:object]}#{params[:method]}#{params[:uniqid]}”
if (params[:field] == “other”)
page.insert_html :bottom, “#{tag}”, content_tag(“option”, “#{params
[:value]}”)
page << “$(’#{tag}’).selectedIndex = $(’#{tag}’).length-1;”
end
page << “if (Element.visible(’#{tag}_other_div’)) Effect.SlideUp(’#
{tag}_other_div’);”
page << “$(‘submit’).disabled = false;”
==== app/views/assets/test.rhtml ====
<%= select_from_db(‘asset’,‘head’,’’, options = { :include_blank =>
true, :include_other => true}, html_options = { :uniqid => “48” }) %>