Example code for select_from_db (a.k.a. combo box)


#1

I’m not asking for help this time! :slight_smile: :slight_smile: 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” }) %>