HoboFields 1.3 needs updating to handle (legacy) field names containing spaces
Reported by Tim Griffin | December 16th, 2011 @ 06:37 PM
In using HoboFields against a legacy database that included a field named "Inuktitut Name", the following error was generated:
../hobo_fields-1.3.0/lib/hobo_fields/extensions/active_record/attribute_methods.rb:34:in `module_eval':
../gems/hobo_fields-1.3.0/lib/hobo_fields/extensions/active_record/attribute_methods.rb:34:
formal argument cannot be a constant (SyntaxError)
def Inuktitut Name; missing_attribute('Inuktitu... ^
Upon consultation with Bryan, it seems that HoboFields' attribute_methods.rb needs a little updating to current ActiveRecord code to handle this case.
Patching the define_read_method in attribute_methods.rb with code from ActiveRecord 3.0.11 seems to deal with this specific error, but it appears that Ruby itself still defines a method name containing a space (making it necessary to call the method using send as in (m.send(:"Inuktitut Name")). As such, I've added a line to remove spaces from the method name being defined, and to downcase it.
Not sure if this is an acceptable solution.
Note: The "symbol" reference in HoboField's original version was changed to "method_name" in the code below.
ActiveRecord::Base.class_eval do
class << self
def can_wrap_with_hobo_type?(attr_name)
if connected?
type_wrapper = try.attr_type(attr_name)
type_wrapper.is_a?(Class) && type_wrapper.not_in?(HoboFields::PLAIN_TYPES.values)
else
false
end
end
# Define an attribute reader method. Cope with nil column.
def define_read_method(method_name, attr_name, column)
cast_code = column.type_cast_code('v') if column
access_code = cast_code ? "(v=@attributes['#{attr_name}']) && #{cast_code}" : "@attributes['#{attr_name}']"
unless attr_name.to_s == self.primary_key.to_s
access_code = access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ")
end
# This is the Hobo hook - add a type wrapper around the field
# value if we have a special type defined
if can_wrap_with_hobo_type?(method_name)
access_code = "val = begin; #{access_code}; end; wrapper_type = self.class.attr_type(:#{attr_name}); " +
"if HoboFields.can_wrap?(wrapper_type, val); wrapper_type.new(val); else; val; end"
end
if cache_attribute?(attr_name)
access_code = "@attributes_cache['#{attr_name}'] ||= begin; #{access_code}; end;"
end
# Where possible, generate the method by evalling a string, as this will result in
# faster accesses because it avoids the block eval and then string eval incurred
# by the second branch.
#
# The second, slower, branch is necessary to support instances where the database
# returns columns with extra stuff in (like 'my_column(omg)').
new_method_name = method_name.gsub(' ', '_').downcase
if new_method_name =~ /^[a-zA-Z_]\w*[!?=]?$/
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__
def _#{new_method_name}
#{access_code}
end
alias #{new_method_name} _#{new_method_name}
STR
else
generated_attribute_methods.module_eval do
define_method("_#{new_method_name}") { eval(access_code) }
alias_method(new_method_name, "_#{new_method_name}")
end
end
end
def define_method_attribute=(attr_name)
if can_wrap_with_hobo_type?(attr_name)
src = "begin; wrapper_type = self.class.attr_type(:#{attr_name}); " +
"if !new_value.is_a?(wrapper_type) && HoboFields.can_wrap?(wrapper_type, new_value); wrapper_type.new(new_value); else; new_value; end; end"
generated_attribute_methods.module_eval("def #{attr_name}=(new_value); write_attribute('#{attr_name}', #{src}); end", __FILE__, __LINE__)
else
super
end
end
end
end
No comments found
Please Sign in or create a free account to add a new ticket.
With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile ยป