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