Upcasing Dynamic Find Methods in Rails

Earlier today I discovered that dynamic finder methods such as `find\_by\_some\_attribute` wouldn’t work with my `UPPER\_CASE` column names in my legacy database tables unless I wrote them as their literal case: `find\_by\_SOME\_ATTRIBUTE`. The hack was as simple for the class level `method\_missing` as it was for the instance method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# This enhances Base's class method
def self.method_missing(method_id, *arguments)
  if match = /find_(all_by|by)_([_a-zA-Z]\w*)/.match(method_id.to_s)
    finder = determine_finder(match)

    attribute_names = extract_attribute_names_from_match(match)
    # just upcase! the names
    attribute_names.each{|name| name.upcase!}
    super unless all_attributes_exists?(attribute_names)

    conditions = construct_conditions_from_arguments(attribute_names, arguments)

    if arguments[attribute_names.length].is_a?(Hash)
      find(finder, { :conditions => conditions }.update(arguments[attribute_names.length]))
    else
      send("find_#{finder}", conditions, *arguments[attribute_names.length..-1]) # deprecated API
    end
  elsif match = /find_or_create_by_([_a-zA-Z]\w*)/.match(method_id.to_s)
    attribute_names = extract_attribute_names_from_match(match)
    # just upcase! the names
    attribute_names.each{|name| name.upcase!}
    super unless all_attributes_exists?(attribute_names)

    find(:first, :conditions => construct_conditions_from_arguments(attribute_names, arguments)) || 
      create(construct_attributes_from_arguments(attribute_names, arguments))
  else
    super
  end
end

I just put this in an abstract model class that is extended by the legacy models and I can now use lower-cased `find\_by` dynamic methods.

Advertisements

Pages

Categories

Copyright ©2008-2013 James E Orchard-Hays, All Rights Reserved

%d bloggers like this: