My Octopress Blog

A blogging framework for hackers.

Serialized Multiple Select in Rails

In the current app i’m working on, I wanted to store multiple values in a single column. I know, violation of the first normal form.. blah blah blah. Save it.

Anyway, I wanted to have a multiple select box that would easily allow me to Manage and update the attributes of the model. Here is my solution.

Create the database table

create_table :tshirt, :force => true do |t|
  t.column :available_colors, :string
  t.column :available_sizes, :string
end

Create the Model

class Tshirt < ActiveRecord::Base
  serialize :available_colors, Array
  serialize :available_sizes, Array
end

Create the YAML Options Hash

I use an options.yml file in the config directory to setup the options for the object. A containing hash is created using the name of the object, and then the sub-hashes match the name of the column.

./config/options.yml

tshirt:
  available_colors:
    1: Red
    2: Blue
    3: Green
  available_sizes:
    1: Small
    2: Medium
    3: Large

Load the Options File into the App

In your environment.rb file you have to load the YAML parser and then parse the options.yml file:

require 'yaml'
OPTIONS = YAML::load(File.open("#{RAILS_ROOT}/config/options.yml"))

The Select Box

This is the hard part.

module ActionView
  module Helpers
    module FormOptionsHelper
      include ERB::Util

      def serialized_multiple_select(object, method, choices = {}, options = {}, html_options = {})
        html = []
        html << "<select id=\"#{object}_#{method}\" name=\"#{object}[#{method}]\" multiple=\"multiple\" size=\"5\">"
        html << options_for_select(OPTIONS[object].invert,self.instance_variable_get('@'+object).send(method).collect{|x| x.to_i })
        html << "</select>"
        return html
      end
    end
  end
end

Add the select box to your form

And this is the easy part:

<p>Colors: <%= serialized_multiple_select 'tshirt', 'available_colors' %></p>
<p>Sizes: <%= serialized_multiple_select 'tshirt', 'available_sizes' %></p>

I am pretty sure there are better way to do this, but this one worked for me.

Also, my serialized_multiple_select has options that it doesn’t even use. I should really use them. Please offer feedback if you have any. :)