I found creating search forms in Rails a little awkward because most of the built in Rails form elements expect to work with attributes of an object, whereas for a search form I just needed to pass a set of attributes. The solution was simple – create a temporary object to hold search attributes.
When I first create the class I now use to solve this issue, I just intended to use it for search forms, but I now find I’m using it for other things such as organising the data returned by custom SQL calls.
Here is the class definition. I’ll add a couple of other blog entries to describe how I use it.
# An object used to store data # Attributes can be generated both on initiation and later # Usage # t = TempObject.new('one') # t.one = "Hi!" # puts t.one ---> "Hi!" # t.create_attribute('two') # t.two = "Hello again" # puts t.two ---> "Hello again" class TempObject def initialize(*attribute_names) @attribute_names = Array.new attribute_names.flatten.each do |a| create_attribute(a) end end # Creates a new attribute with a name defined by name # The example below generates two methods: the setter 'two=' and the getter two # # t = TempObject.new # t.create_attribute('two') # t.two = "Hello" # puts t.two ---> "Hello" def create_attribute(name) name = name.to_sym self.class.send(:attr_accessor, name) @attribute_names << name end # Returns a list of the attributes added to this object def attribute_names @attribute_names end # Allows data to be loaded into the attributes from a Hash. # t = TempObject.new(:one, :two) # t.load_data({:one => 1, 'two' => 2, :three => 3}) # puts t.one ---> 1 # puts t.three ---> error no method def load_data(data = nil) if data @attribute_names.each do |a| if value = data[a.to_sym] or value = data[a.to_s] instance_variable_set("@#{a}", value) end end end end # Allows a new object to be created from a hash in one step # All data in hash will be used to populate new object # t = TempObject.new_and_load_all({:one => 1, :two => 2}) # puts t.one ---> 1 def self.new_and_load_all(data) if data.kind_of?(Hash) and data.length > 0 object = self.new(data.keys) object.load_data(data) end return object end # Takes an array of hashes (for example from a connection.select_all # and returns an array of TempOjects created from the hashes def self.create_from_array_of_hashes(array) array.collect{|hash| TempObject.new_and_load_all(hash)} end def report report_data = Array.new for attribute in attribute_names value = send(attribute) value = value.strftime("%a %d-%b-%y %H:%M") if value.kind_of? Time report_data << "#{attribute.to_s.capitalize} : #{value}" if value end return report_data end end