Forum: Ruby on Rails Example code for select_from_db (a.k.a. combo box)

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Peter T Bosse II (Guest)
on 2006-02-28 00:58
(Received via mailing list)
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" }) %>
This topic is locked and can not be replied to.